Skip to content

Instantly share code, notes, and snippets.

@mwgamera
Created April 26, 2020 04:32
Show Gist options
  • Save mwgamera/2adedee9a75f253dc7a2fb1c57385c3b to your computer and use it in GitHub Desktop.
Save mwgamera/2adedee9a75f253dc7a2fb1c57385c3b to your computer and use it in GitHub Desktop.
#!/usr/bin/env perl
# Fix some JPG data in SWF file so that swfrender doesn't trip on it.
# klg, Apr 2020
use strict;
use warnings;
use IO::Compress::Deflate;
use IO::Uncompress::Inflate;
my $src = \*STDIN;
my $dst = \*STDOUT;
open $src, '<', shift or die $! if @ARGV;
# read the uncompressed part of the header
read $src, $_, 8 or die $!;
my ($magic, $version, $size) = unpack 'A3CV';
die 'Not an SWF file.' unless $magic =~ /^[FCZ]WS$/;
die 'LZMA not supported' if $magic eq 'ZWS';
if ($magic eq 'CWS') {
$src = IO::Uncompress::Inflate->new($src)
or die "inflate: $!";
}
print $dst pack 'A3CV', 'CWS', $version, $size or die $!;
$dst = IO::Compress::Deflate->new($dst) or die "deflate: $!";
# read the rest of a header and copy it out
read $src, $_, 1 or die $!;
print $dst $_ or die $!;
read $src, $_, (((ord >> 3) * 4 + 5 - 1) >> 3) + 4 or die $!;
print $dst $_ or die $!;
# read and copy all tags, modifying some
until (eof $src) {
read $src, $_, 2 or die $!;
print $dst $_ or die $!;
my $tag = unpack 'v';
my $len = $tag & 0x3f;
if ($len == 0x3f) {
read $src, $_, 4, or die $!;
print $dst $_ or die $!;
$len = unpack 'V';
}
$tag >>= 6;
if ($len) {
read $src, $_, $len or die $!;
$_ = fixjpgtags($tag, $_);
print $dst $_ or die $!;
}
}
sub fixjpgtags {
my ($tag, $data) = @_;
if ($tag == 6) { # DefineBits
substr($data, 2) = fixjpgdata(substr $data, 2);
} elsif ($tag == 8) { # JPEGTables
$data = fixjpgdata($data);
} elsif ($tag == 21) { # DefineBitsJPEG2
substr($data, 2) = fixjpgdata(substr $data, 2);
} elsif ($tag == 35) { # DefineBitsJPEG3
my $len = unpack 'x2V', $data;
substr($data, 6, $len) = fixjpgdata(substr $data, 6, $len);
}
return $data;
}
=for comment
SWF File Format Specification says:
"The data in this tag begins with the JPEG SOI marker 0xFF, 0xD8 and ends with
the EOI marker 0xFF, 0xD9. Before version 8 of the SWF file format, SWF files
could contain an erroneous header of 0xFF, 0xD9, 0xFF, 0xD8 before the JPEG SOI
marker. In addition to specifying JPEG data, DefineBitsJPEG2 can also contain
PNG image data and non-animated GIF89a."
=for comment
The offending files contained valid JFIF prefixed by EOI, i.e. data that
started with FF D9 FF D8 FF E0... Swftools would remove FF D9 FF D8 and
then complain that the rest starts with FF E0 so it does not look like JPEG.
Normalize things to start with single SOI, and pad with zeros to keep sizes
and alignment unchanged.
=cut
sub fixjpgdata {
local ($_) = @_;
return $_ if /\A\x89PNG|\AGIF/;
m/\A((\xff[\xd8\xd9])+)/ or die 'unexpected data in tag';
my $L = length $1;
return "\xff\xd8" . substr($_, $L) . "\0" x ($L-2);
}
1;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment