Skip to content

Commit

Permalink
Add insert_movieclip method
Browse files Browse the repository at this point in the history
  • Loading branch information
Nishibayashi Takuji committed May 24, 2011
1 parent 1f0358f commit aeed3a3
Showing 1 changed file with 210 additions and 0 deletions.
210 changes: 210 additions & 0 deletions lib/SWF/Editor.pm
Expand Up @@ -9,6 +9,9 @@ use SWF::BinStream;
use SWF::Editor::Tag;
use SWF::Editor::Tag::FrameLabel;
use SWF::Editor::Utils::Tag;
use SWF::Editor::Utils::Header;
use SWF::Editor::Utils::IOBit;


our $VERSION = '0.01';
=pod
Expand Down Expand Up @@ -38,8 +41,26 @@ SWF::Editor - SWF file editor
SWF::Editor is SWF file editor.
=head1 METHODS
=cut

our %HAS_CID_TAGS = (
DefineBits => 1,
DefineBitsJPEG2 => 1,
DefineBitsJPEG3 => 1,
DefineBitsLossless => 1,
DefineMorphShape => 1,
DefineShape => 1,
DefineShape2 => 1,
DefineShape3 => 1,
DefineText => 1,
DefineTextEdit => 1,
DefineEditText => 1,
DefineFont2 => 1,
DefineSprite => 1,
);


has compressed => (is => 'rw', isa => 'Bool', lazy_build => 1);
has file => (is => 'ro', isa => 'Str');
Expand Down Expand Up @@ -233,6 +254,195 @@ sub get_binary {
$raw;
}

=pod
=head2 insert_movieclip
Insert movie clip which instance of SWF::Editor
my $swf = SWF::Editor->new(file => '/path/to/swf/movie');
my $insert_swf = SWF::Editor->new(file => '/path/to/insert/swf/movie');
my $matrix = SWF::Editor::Variable::Matrix->new(translate_x => 100, translate_y => 200);
#Insert $insert_swf into $swf at frame 2
$swf->insert_movieclip(insert_swf => $insert_swf, frame_num => 2, name => 'hoge', matrix => $matrix);
=cut
sub insert_movieclip {
args my $self,
my $insert_swf => 'SWF::Editor',
my $frame_num => 'Int',
my $matrix => { isa => 'SWF::Editor::Variable::Matrix', optional => 1 },
my $name => { isa => 'Str', optional => 1 };

$insert_swf = $insert_swf->clone;

my @tags = @{$self->tags};

#Parse max Character ID and max Depth at once.
if ( !$self->{parsed_already} ) {
for my $tag (@tags) {
my $tag_name = get_tag_name($tag->type);
if( $HAS_CID_TAGS{$tag_name} ) {
my $cid = $tag->cid;
$self->{max_cid} = $cid if !defined $self->{max_cid} || $self->{max_cid} < $cid;
}
if ( $tag_name eq 'PlaceObject2' ) {
#depth
my $depth = unpack("v", substr( $tag->data, 1, 2 ) );
$self->{max_depth} = $depth if !defined $self->{max_depth} || $self->{max_depth} < $depth;
}
}
}
$self->{parsed_already} = 1;

my $current_cid = $self->{max_cid} + 1;
my $current_depth = $self->{max_depth} + 1;
my %new_cid;
for my $insert_tag (@{$insert_swf->tags}) {
my $tag_name = get_tag_name($insert_tag->type);
if ( $tag_name eq 'SetBackgroundColor' || $tag_name eq 'FileAttributes') {
#Skip tag
next;
}
my $data = $insert_tag->data;
#Tags which has character id
if ( $HAS_CID_TAGS{$tag_name} ) {
my $old_cid = $insert_tag->cid;
$insert_tag->cid($current_cid);
$new_cid{$old_cid} = $current_cid;
substr( $data, 0, 2, pack("v",$current_cid) );
$current_cid++;
}
if ( $tag_name eq 'PlaceObject2' ) {
#Get 7th bit ( has character id flag )
my $has_character = ( ord( substr( $data, 0, 1 ) ) >> 1 ) & 1;
my $depth = unpack("v", substr( $data, 1, 2 ) );
if ( $depth <= $current_depth ) {
substr( $data, 1, 2, pack("v",$current_depth) );
$current_depth++;
} elsif( $depth > $current_depth ) {
$current_depth = $depth + 1;
}
if( $has_character ) {
my $cid = unpack( "v", substr( $data, 3, 2 ) );
#Replace character id
if( defined $new_cid{$cid} ) {
my $replace_cid = $new_cid{$cid};
substr( $data, 3, 2, pack("v",$replace_cid) );
}
}
#Replace binary data
my $flg_bit = substr($data,0,1);
my $flg_bits = [split //, unpack("B8",$flg_bit)];
my $name_offset = 3;
my $name_length = 0;
if($flg_bits->[6]) {
$name_offset += 2;
}
my $matrix_offset = $name_offset;
if($flg_bits->[5]) {
#Calculate matrix length
my $iobit = SWF::Editor::Utils::IOBit->new( data => substr( $data, $name_offset ) );
if ( $iobit->get_ui_bit ) {
my $length = $iobit->get_ui_bits(5);
$iobit->add_bit_offset($length * 2);
}
if ( $iobit->get_ui_bit ) {
my $length = $iobit->get_ui_bits(5);
$iobit->add_bit_offset($length * 2);
}
my $length = $iobit->get_ui_bits(5);
$iobit->add_bit_offset($length * 2);
$iobit->byte_align;
$name_offset += $iobit->byte_offset;
}
if ( $matrix ) {
#Replace matrix
my $length = $name_offset - $matrix_offset;
my $matrix_binary = $matrix->get_binary;
$flg_bits->[5] = 1;
$name_offset = $matrix_offset + length $matrix_binary;
substr( $data, $matrix_offset, $length, $matrix_binary );
}
if($flg_bits->[4]) {
#Calculate cxformwithalpha length
my $iobit = SWF::Editor::Utils::IOBit->new( data => substr( $data, $name_offset ) );
$iobit->add_bit_offset(2);
my $length = $iobit->get_ui_bits(4);
$iobit->add_bit_offset($length * 4);
$iobit->byte_align;
$name_offset += $iobit->byte_offset;
}
if($flg_bits->[3]) {
$name_offset += 2;
}
if($flg_bits->[2]) {
#Calculate name length
my $iobit = SWF::Editor::Utils::IOBit->new( data => substr( $data, $name_offset ) );
while(1) {
my $str_code = $iobit->get_ui8;
if( $str_code ) {
$name_length++;
} else {
$name_length++;
last;
}
}
}
if ( $name ) {
#Insert or replace name
$flg_bits->[2] = 1;
substr( $data, $name_offset, $name_length, $name.chr(0) );
}
#Update flag bit
substr( $data, 0, 1, pack("B8", join('',@$flg_bits)) );
}
if( $tag_name eq 'DefineSprite' ) {
my $mc_iobit = SWF::Editor::Utils::IOBit->new( data => $data );
#Skip character id ( ui 16bit ) and frame count ( ui 16bit )
$mc_iobit->add_byte_offset(4);
while(1) {
my $header = $mc_iobit->get_ui16_le;
my $is_long_header = is_long_header($header);
my $length = $is_long_header ? $mc_iobit->get_ui32_le : $header & 0x3F;
my $offset = $mc_iobit->byte_offset;
my $mc_data = $mc_iobit->get_data($length);
my $type = $header >> 6;
my $mc_tag_name = get_tag_name($type);
if ( $mc_tag_name eq 'PlaceObject2' ) {
#Get flag bit
my $has_character = ( ord( substr( $mc_data, 0, 1 ) ) >> 1 ) & 1;
if( $has_character ) {
my $cid = unpack( "v", substr( $mc_data, 3, 2 ) );
#Replace character id
if( defined $new_cid{$cid} ) {
my $replace_cid = $new_cid{$cid};
substr( $mc_data, 3, 2, pack("v",$replace_cid) );
my $iobit_data = $mc_iobit->data;
substr( $iobit_data, $offset, length $mc_data, $mc_data );
$mc_iobit->data($iobit_data);
}
}
}
if ( $mc_tag_name eq 'End' ) {
last;
}
}
$data = $mc_iobit->data;
}
if ( $tag_name eq 'ShowFrame' ) {
last;
}
$insert_tag->data($data);
$self->insert_tag_by_frame_no( $frame_num => $insert_tag );
}
$self->{max_cid} = $current_cid;
$self->{max_depth} = $current_depth;
return $self;
}

1;
__PACKAGE__->meta->make_immutable;
__END__
=head1 AUTHOR
Expand Down

0 comments on commit aeed3a3

Please sign in to comment.