furnace-swf 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,5 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
5
+ *.swf
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in furnace-swf.gemspec
4
+ gemspec
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,96 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "rubygems"
4
+ require "bundler/setup"
5
+
6
+ $: << File.join(File.dirname(__FILE__), '..', 'lib')
7
+
8
+ require "trollop"
9
+ require "furnace-swf"
10
+
11
+ include Furnace
12
+
13
+ SUBCOMMANDS = %w(abclist abcextract abcreplace)
14
+
15
+ opts = Trollop::options do
16
+ version "furnace-swf #{SWF::VERSION}"
17
+ banner <<-EOS
18
+ furnace-swf is a processing tool which operates on Flash SWF files.
19
+
20
+ Possible subcommands: #{SUBCOMMANDS.join ' '}
21
+ Try #{__FILE__} subcommand --help.
22
+
23
+ Usage: #{__FILE__} [options] <subcommand>
24
+ EOS
25
+
26
+ opt :input, "SWF input file", :type => :io
27
+ opt :trace, "Trace reading", :default => false
28
+
29
+ stop_on SUBCOMMANDS
30
+ end
31
+
32
+ subcommand = ARGV.shift
33
+ subopts = case subcommand
34
+ when 'abclist'
35
+ Trollop::options do
36
+ end
37
+
38
+ when 'abcextract'
39
+ Trollop::options do
40
+ opt :name, "ABC tag name", :type => :string, :required => true
41
+ opt :output, "ABC output file", :type => :string, :required => true
42
+ end
43
+
44
+ when 'abcreplace'
45
+ Trollop::options do
46
+ opt :name, "ABC tag name", :type => :string, :required => true
47
+ opt :input, "ABC input file", :type => :io, :required => true
48
+ opt :output, "Combined SWF output file", :type => :string, :required => true
49
+ end
50
+ end
51
+
52
+ Trollop::die "Option --input is required" unless opts[:input]
53
+
54
+ swf = nil
55
+ File.open(opts[:input]) do |file|
56
+ swf = SWF::File.new
57
+
58
+ if opts[:trace]
59
+ BinData::trace_reading do
60
+ swf.read(file)
61
+ end
62
+ else
63
+ swf.read(file)
64
+ end
65
+ end
66
+
67
+ case subcommand
68
+ when 'abclist'
69
+ puts "ABC tags:"
70
+
71
+ swf.stream.tags(SWF::DoABCTag).each do |tag|
72
+ puts " #{tag.name.inspect}: #{tag.bytecode.length} byte(s)"
73
+ end
74
+
75
+ when 'abcextract'
76
+ if tag = swf.stream.tags(SWF::DoABCTag).find { |tag| tag.name == subopts[:name] }
77
+ File.open(subopts[:output], 'w') do |f|
78
+ f.write tag.bytecode
79
+ end
80
+ else
81
+ puts "Tag #{subopts[:name].inspect} was not found"
82
+ exit 1
83
+ end
84
+
85
+ when 'abcreplace'
86
+ if tag = swf.stream.tags(SWF::DoABCTag).find { |tag| tag.name == subopts[:name] }
87
+ tag.bytecode = subopts[:input].read
88
+
89
+ File.open(subopts[:output], 'w') do |f|
90
+ swf.write f
91
+ end
92
+ else
93
+ puts "Tag #{subopts[:name].inspect} was not found"
94
+ exit 1
95
+ end
96
+ end
@@ -0,0 +1,22 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+
4
+ Gem::Specification.new do |s|
5
+ s.name = "furnace-swf"
6
+ s.version = "0.0.1"
7
+ s.authors = ["Peter Zotov", "Sergey Gridassov"]
8
+ s.email = ["whitequark@whitequark.org", "grindars@gmail.com"]
9
+ s.homepage = "http://github.com/whitequark/furnace-swf"
10
+ s.summary = %q{Flash SWF file reader and writer}
11
+ s.description = %q{furnace-swf allows one to load, modify and write back } <<
12
+ %q{Flash SWF files. It can be used with furnace-avm2 in } <<
13
+ %q{order to achieve impressive results.}
14
+
15
+ s.files = `git ls-files`.split("\n")
16
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
17
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
18
+ s.require_paths = ["lib"]
19
+
20
+ s.add_runtime_dependency "bindata"
21
+ s.add_runtime_dependency "trollop"
22
+ end
@@ -0,0 +1,8 @@
1
+ module Furnace
2
+ module SWF
3
+ end
4
+ end
5
+
6
+ require "furnace-swf/version"
7
+
8
+ require "furnace-swf/swf"
@@ -0,0 +1,17 @@
1
+ require "bindata"
2
+
3
+ require_relative "swf/sbit"
4
+ require_relative "swf/ubit"
5
+
6
+ require_relative "swf/rect"
7
+
8
+ require_relative "swf/tag_wrapper"
9
+ require_relative "swf/tag"
10
+
11
+ Dir[File.join(File.dirname(__FILE__), 'swf', 'tags', '*.rb')].each do |tag|
12
+ require tag
13
+ end
14
+
15
+ require_relative "swf/header"
16
+ require_relative "swf/stream"
17
+ require_relative "swf/file"
@@ -0,0 +1,40 @@
1
+ require 'zlib'
2
+
3
+ module Furnace::SWF
4
+ class File < BinData::Record
5
+ header :header
6
+ stream :stream
7
+
8
+ def do_read(io)
9
+ instantiate_all_objs
10
+
11
+ header = find_obj_for_name(:header)
12
+ stream = find_obj_for_name(:stream)
13
+
14
+ header.do_read(io)
15
+
16
+ case header.signature
17
+ when 'FWS'
18
+ stream.do_read io
19
+ when 'CWS'
20
+ uncompressed = Zlib.inflate(io.read_all_bytes)
21
+ stream.do_read BinData::IO.new(StringIO.new(uncompressed))
22
+ else
23
+ raise ArgumentError, "invalid signature"
24
+ end
25
+ end
26
+
27
+ def do_write(io)
28
+ instantiate_all_objs
29
+
30
+ header = find_obj_for_name(:header)
31
+ stream = find_obj_for_name(:stream)
32
+
33
+ header.signature = 'FWS'
34
+ header.file_length = header.num_bytes + stream.real_num_bytes
35
+
36
+ header.do_write(io)
37
+ stream.do_write(io)
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,9 @@
1
+ module Furnace::SWF
2
+ class Header < BinData::Record
3
+ endian :little
4
+
5
+ string :signature, :length => 3
6
+ uint8 :version
7
+ uint32 :file_length
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ module Furnace::SWF
2
+ class Rect < BinData::Record
3
+ bit5 :num_bits
4
+ sbit :x_min, :length => :num_bits
5
+ sbit :x_max, :length => :num_bits
6
+ sbit :y_min, :length => :num_bits
7
+ sbit :y_max, :length => :num_bits
8
+ end
9
+ end
@@ -0,0 +1,21 @@
1
+ module Furnace::SWF
2
+ class Sbit < BinData::BasePrimitive
3
+ mandatory_parameter :length
4
+
5
+ def do_write(io)
6
+ io.writebits(_value, eval_parameter(:length), :big)
7
+ end
8
+
9
+ def do_num_bytes
10
+ eval_parameter(:length) / 8.0
11
+ end
12
+
13
+ def read_and_return_value(io)
14
+ io.readbits(eval_parameter(:length), :big)
15
+ end
16
+
17
+ def sensible_default
18
+ 0
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,25 @@
1
+ module Furnace::SWF
2
+ class Stream < BinData::Record
3
+ endian :little
4
+
5
+ rect :frame_size
6
+ uint8 :frame_rate_lo
7
+ uint8 :frame_rate_hi
8
+ uint16 :frame_count
9
+
10
+ array :tag_wrappers, :type => :tag_wrapper, :read_until => :eof
11
+
12
+ def frame_rate
13
+ BigDecimal.new(frame_rate_hi) +
14
+ BigDecimal.new(frame_rate_lo) / 100
15
+ end
16
+
17
+ def tags(type)
18
+ tag_wrappers.select { |tw| tw.content.is_a? type }.map(&:content)
19
+ end
20
+
21
+ def real_num_bytes
22
+ num_bytes + tag_wrappers.map(&:content_size).reduce(0, :+)
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,34 @@
1
+ module Furnace::SWF
2
+ class Tag < BinData::Record
3
+ mandatory_parameter :stream
4
+
5
+ endian :little
6
+
7
+ REGISTRY = {}
8
+
9
+ def self.exists_for?(type)
10
+ REGISTRY.has_key? type
11
+ end
12
+
13
+ def self.instantiate(type, parent, stream)
14
+ REGISTRY[type].new({ stream: stream }, parent)
15
+ end
16
+
17
+ # DSL
18
+
19
+ class << self
20
+ def type(id)
21
+ Tag::REGISTRY[id] = self
22
+
23
+ define_method(:type) do
24
+ id
25
+ end
26
+ end
27
+ end
28
+
29
+ def initialize_instance
30
+ super
31
+ @stream = @params[:stream]
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,85 @@
1
+ module Furnace::SWF
2
+ class TagWrapper < BinData::Record
3
+ endian :little
4
+
5
+ uint16 :type_and_length
6
+ int32 :long_length, :onlyif => lambda { short_length == 0x3f }
7
+
8
+ attr_accessor :content
9
+
10
+ # Accessors for braindead format.
11
+
12
+ def type
13
+ type_and_length >> 6
14
+ end
15
+
16
+ def type=(value)
17
+ self.type_and_length = (type_and_length & 0x3f) | (value << 6)
18
+ end
19
+
20
+ def short_length
21
+ type_and_length & 0x3f
22
+ end
23
+
24
+ def short_length=(value)
25
+ self.type_and_length = (type_and_length & 0xfffc) | (value & 0x3f)
26
+ end
27
+
28
+ def real_length
29
+ short_length == 0x3f ? long_length : short_length
30
+ end
31
+
32
+ def real_length=(value)
33
+ if value > 0x3f
34
+ self.short_length = 0x3f
35
+ self.long_length = value
36
+ else
37
+ self.short_length = value
38
+ self.long_length = 0
39
+ end
40
+ end
41
+
42
+ # Nested reads/writes.
43
+
44
+ def do_read(io)
45
+ super
46
+
47
+ orig_offset = io.offset
48
+
49
+ if Tag.exists_for?(type)
50
+ @content = Tag.instantiate(type, self, parent)
51
+ @content.do_read io
52
+
53
+ if io.offset - orig_offset != real_length
54
+ raise "Invalid tag #{@content}"
55
+ end
56
+ else
57
+ @content = io.readbytes(real_length)
58
+ end
59
+ end
60
+
61
+ def do_write(io)
62
+ super
63
+
64
+ if Tag.exists_for?(type)
65
+ @content.do_write io
66
+ else
67
+ io.writebytes @content
68
+ end
69
+ end
70
+
71
+ def do_num_bytes
72
+ self.real_length = content_size
73
+
74
+ super
75
+ end
76
+
77
+ def content_size
78
+ if @content.is_a? Tag
79
+ @content.num_bytes
80
+ else
81
+ @content.length
82
+ end
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,9 @@
1
+ module Furnace::SWF
2
+ class DefineBinaryTag < Tag
3
+ type 87
4
+
5
+ uint16 :tag
6
+ uint32 :reserved
7
+ string :data, :read_length => lambda { parent.real_length - 6 }
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ module Furnace::SWF
2
+ class DoABCTag < Tag
3
+ type 82
4
+
5
+ uint32 :flags
6
+ stringz :name
7
+ string :bytecode, :read_length => lambda { parent.real_length - 4 - name.length - 1 }
8
+ end
9
+ end
@@ -0,0 +1,11 @@
1
+ module Furnace::SWF
2
+ class SymbolClassTag < Tag
3
+ type 76
4
+
5
+ uint16 :num_symbols, :value => lambda { symbols.count }
6
+ array :symbols, :initial_length => :num_symbols do
7
+ uint16 :tag
8
+ stringz :name
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,21 @@
1
+ module Furnace::SWF
2
+ class Ubit < BinData::BasePrimitive
3
+ mandatory_parameter :length
4
+
5
+ def do_write(io)
6
+ io.writebits(_value, eval_parameter(:length), :little)
7
+ end
8
+
9
+ def do_num_bytes
10
+ eval_parameter(:length) / 8.0
11
+ end
12
+
13
+ def read_and_return_value(io)
14
+ io.readbits(eval_parameter(:length), :big)
15
+ end
16
+
17
+ def sensible_default
18
+ 0
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,3 @@
1
+ module Furnace::SWF
2
+ VERSION = "0.0.1"
3
+ end
metadata ADDED
@@ -0,0 +1,91 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: furnace-swf
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Peter Zotov
9
+ - Sergey Gridassov
10
+ autorequire:
11
+ bindir: bin
12
+ cert_chain: []
13
+ date: 2012-02-04 00:00:00.000000000 Z
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: bindata
17
+ requirement: &71683110 !ruby/object:Gem::Requirement
18
+ none: false
19
+ requirements:
20
+ - - ! '>='
21
+ - !ruby/object:Gem::Version
22
+ version: '0'
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: *71683110
26
+ - !ruby/object:Gem::Dependency
27
+ name: trollop
28
+ requirement: &71682470 !ruby/object:Gem::Requirement
29
+ none: false
30
+ requirements:
31
+ - - ! '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: *71682470
37
+ description: furnace-swf allows one to load, modify and write back Flash SWF files.
38
+ It can be used with furnace-avm2 in order to achieve impressive results.
39
+ email:
40
+ - whitequark@whitequark.org
41
+ - grindars@gmail.com
42
+ executables:
43
+ - furnace-swf
44
+ extensions: []
45
+ extra_rdoc_files: []
46
+ files:
47
+ - .gitignore
48
+ - Gemfile
49
+ - Rakefile
50
+ - bin/furnace-swf
51
+ - furnace-swf.gemspec
52
+ - lib/furnace-swf.rb
53
+ - lib/furnace-swf/swf.rb
54
+ - lib/furnace-swf/swf/file.rb
55
+ - lib/furnace-swf/swf/header.rb
56
+ - lib/furnace-swf/swf/rect.rb
57
+ - lib/furnace-swf/swf/sbit.rb
58
+ - lib/furnace-swf/swf/stream.rb
59
+ - lib/furnace-swf/swf/tag.rb
60
+ - lib/furnace-swf/swf/tag_wrapper.rb
61
+ - lib/furnace-swf/swf/tags/define_binary_data_tag.rb
62
+ - lib/furnace-swf/swf/tags/do_abc_tag.rb
63
+ - lib/furnace-swf/swf/tags/symbol_class_tag.rb
64
+ - lib/furnace-swf/swf/ubit.rb
65
+ - lib/furnace-swf/version.rb
66
+ homepage: http://github.com/whitequark/furnace-swf
67
+ licenses: []
68
+ post_install_message:
69
+ rdoc_options: []
70
+ require_paths:
71
+ - lib
72
+ required_ruby_version: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ! '>='
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
78
+ required_rubygems_version: !ruby/object:Gem::Requirement
79
+ none: false
80
+ requirements:
81
+ - - ! '>='
82
+ - !ruby/object:Gem::Version
83
+ version: '0'
84
+ requirements: []
85
+ rubyforge_project:
86
+ rubygems_version: 1.8.10
87
+ signing_key:
88
+ specification_version: 3
89
+ summary: Flash SWF file reader and writer
90
+ test_files: []
91
+ has_rdoc: