furnace-swf 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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: