swf_file 0.1.0

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.
data/.gitignore ADDED
@@ -0,0 +1,3 @@
1
+ .DS_Store
2
+ .bundle
3
+ pkg
data/LICENSE ADDED
@@ -0,0 +1,28 @@
1
+ This gem is based on Dennis Zhuang's swf-util library, made available at http://code.google.com/p/swf-util/, under the Apache License 2.0 (vide http://www.apache.org/licenses/LICENSE-2.0).
2
+
3
+ The fixture files smallgoat.jpg, clicktag-decompressed.swf, clicktag.swf, originally made available under the MIT license (vide http://www.opensource.org/licenses/mit-license.php) at http://github.com/2performant/swiff, are included in this gem, without modification, under their original copyright © 2010 held by 2Perfomant.
4
+
5
+ All modifications and additions contained within this gem, made available at http://github.com/DBA/swfheader, are licensed under the following terms and conditions:
6
+
7
+ Copyright (c) 2010 Diogo Almeida
8
+
9
+ Permission is hereby granted, free of charge, to any person
10
+ obtaining a copy of this software and associated documentation
11
+ files (the "Software"), to deal in the Software without
12
+ restriction, including without limitation the rights to use,
13
+ copy, modify, merge, publish, distribute, sublicense, and/or sell
14
+ copies of the Software, and to permit persons to whom the
15
+ Software is furnished to do so, subject to the following
16
+ conditions:
17
+
18
+ The above copyright notice and this permission notice shall be
19
+ included in all copies or substantial portions of the Software.
20
+
21
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
23
+ OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
25
+ HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
26
+ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
28
+ OTHER DEALINGS IN THE SOFTWARE.
data/README ADDED
@@ -0,0 +1,27 @@
1
+ ==Introduction
2
+ Based on the swfutil lib, by Dennis Zhuang, the SWF File is lightweight gem to read swf file headers from within a Ruby application.
3
+
4
+ ==Ruby compatibility
5
+ Target version: 1.9.2dev
6
+ Also compatible with: 1.9.1-p376 and 1.8.7-p
7
+
8
+ Not tested with versions under 1.8.7-p. Should you use this lib with other ruby versions, please provide feedback.
9
+
10
+ ==Install
11
+ gem install swf_file
12
+
13
+ ==LICENSE
14
+ Please refer to the LICENSE file.
15
+
16
+ ==Example
17
+ TODO
18
+
19
+ ==Issues, improvements, feedback an suggestions
20
+ To report issues, please use GitHub's issue manager (http://github.com/DBA/swf_file/issues). Meanwhile, feel free to fork the project and submit your modifications.
21
+
22
+ Should you wish to contact me directly, please use GitHub's message box or the email available at the Rakefile.
23
+
24
+ ==Pending
25
+ * Cleanup the class PackedBitObject, which still suffers from the pure import from SwfUtil
26
+ * Modularize SwfHeader a bit more
27
+ * Docs
data/Rakefile ADDED
@@ -0,0 +1,28 @@
1
+ require 'rake'
2
+
3
+ begin
4
+ require 'jeweler'
5
+ Jeweler::Tasks.new do |gemspec|
6
+ gemspec.name = "swf_file"
7
+ gemspec.summary = "SWF File is lightweight gem to read swf file headers from within a Ruby application"
8
+ gemspec.description = "Based on the swfutil lib, by Dennis Zhuang, the SWF File is lightweight gem to read swf file headers from within a Ruby application. This gem is fully written in Ruby and is compatible with Ruby v1.9.x"
9
+ gemspec.email = "dba@gnomeslab.com"
10
+ gemspec.homepage = "http://github.com/DBA/swf_file"
11
+ gemspec.authors = ["DBA"]
12
+
13
+ # dependencies defined in Gemfile
14
+ end
15
+ rescue LoadError
16
+ puts "Jeweler not available. Install it with: gem install jeweler"
17
+ end
18
+
19
+ require 'rake/testtask'
20
+ #test_files_pattern = 'test/{unit,functional,other,matchers}/**/*_test.rb'
21
+ test_files_pattern = 'test/unit/swf_file_test.rb'
22
+ Rake::TestTask.new do |t|
23
+ t.libs << 'lib'
24
+ t.pattern = test_files_pattern
25
+ t.verbose = true
26
+ end
27
+
28
+ task :default => :test
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.0
Binary file
Binary file
Binary file
@@ -0,0 +1,25 @@
1
+ module Compression
2
+ private
3
+ def buffer_compressed?(memoize_result = true)
4
+ if memoize_result
5
+ @compressed ||= @buffer[0].ord == ?C.ord
6
+ else
7
+ @buffer[0].ord == ?C.ord
8
+ end
9
+ end
10
+
11
+ def decompress_buffer!
12
+ return @buffer unless buffer_compressed?(false)
13
+
14
+ _buffer = @buffer # local buffer copy
15
+ _buffer = Zlib::Inflate.new.inflate strip_buffer_header(_buffer)
16
+ _buffer = _buffer[0,8] + _buffer
17
+ _buffer[0] = ?F
18
+
19
+ @buffer = _buffer
20
+ end
21
+
22
+ def strip_buffer_header(buffer)
23
+ buffer[8, buffer.size - 8]
24
+ end
25
+ end
@@ -0,0 +1,30 @@
1
+ module Conversions
2
+ module Twips
3
+ def self.from_pixels(pixels)
4
+ pixels * 20
5
+ end
6
+ end
7
+
8
+ module Pixels
9
+ def self.from_twips(twips)
10
+ twips / 20
11
+ end
12
+ end
13
+
14
+ module Hash
15
+ def self.from_swf_header(header)
16
+ { file: header.file,
17
+ signature: header.signature,
18
+ version: header.version,
19
+ avm_version: header.avm_version,
20
+ size: header.size,
21
+ bit_count: header.bit_count,
22
+ xmax: header.xmax,
23
+ ymax: header.ymax,
24
+ width: header.width,
25
+ height: header.height,
26
+ frame_rate: header.frame_rate,
27
+ frame_count: header.frame_count }
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,54 @@
1
+ # TODO: Needs refactoring & cleanup
2
+
3
+ class PackedBitObject
4
+ attr_accessor :bitIndex, :byteIndex, :value, :nextBitIndex, :nextByteIndex, :nextByteBoundary
5
+
6
+ def initialize(bitMarker,byteMarker,decimalValue)
7
+ @bitIndex = bitMarker;
8
+ @byteIndex = byteMarker;
9
+ @value = decimalValue;
10
+ @nextBitIndex = bitMarker;
11
+ if ( bitMarker <= 7 )
12
+ @nextBitIndex+=1
13
+ @nextByteIndex =byteMarker
14
+ @nextByteBoundary = (byteMarker+=1)
15
+ else
16
+ @nextBitIndex = 0
17
+ @nextByteIndex+=1
18
+ @nextByteBoundary = @nextByteIndex;
19
+ end
20
+ end
21
+
22
+ def self.from_packed_bits(bytes, byte_marker, bit_marker, length)
23
+ total = 0
24
+ shift = 7 - bit_marker
25
+ counter = 0
26
+ bit_index = bit_marker
27
+ byte_index = byte_marker
28
+
29
+ while counter<length
30
+ (bit_marker...8).each do |i|
31
+ bit =((bytes[byte_marker].ord & 0xff ) >> shift ) & 1
32
+ total = ( total << 1 ) + bit
33
+ bit_index = i
34
+ shift-=1
35
+ counter+=1
36
+
37
+ if counter==length
38
+ break
39
+ end
40
+ end
41
+
42
+ byte_index = byte_marker
43
+ byte_marker+=1
44
+ bit_marker = 0
45
+ shift = 7
46
+ end
47
+
48
+ pbo = PackedBitObject.new(bit_index, byte_index, total)
49
+
50
+ yield pbo if block_given?
51
+
52
+ pbo
53
+ end
54
+ end
@@ -0,0 +1,2 @@
1
+ module Parser
2
+ end
@@ -0,0 +1,97 @@
1
+ class SwfHeader
2
+ include Compression
3
+
4
+ attr_reader :file, :signature, :version, :avm_version, :size, :bit_count,
5
+ :xmax, :ymax, :width, :height,
6
+ :frame_rate, :frame_count
7
+
8
+ def initialize(swf_file)
9
+ @file = swf_file
10
+ parse_header
11
+ parse_packed_bits
12
+ end
13
+
14
+ def compressed?(memoize_result = true)
15
+ buffer_compressed?(memoize_result)
16
+ end
17
+
18
+ # Returns the duration in milliseconds
19
+ def duration
20
+ ((@frame_count / @frame_rate.to_f).round(5) * 1000).round
21
+ end
22
+
23
+ def to_s
24
+ "#{@file} #{@width}x#{@height} #{@frame_rate}fps"
25
+ end
26
+
27
+ def to_hash
28
+ Conversions::Hash.from_swf_header self
29
+ end
30
+
31
+ alias :inspect :to_hash
32
+
33
+ private
34
+ def parse_header
35
+ @buffer, @size = get_swf_buffer_and_size
36
+ raise RuntimeError, "The provided file does not appear to be an SWF", caller unless swf?
37
+
38
+ @signature = @buffer[0,3]
39
+ @version = @buffer[3].ord
40
+
41
+ decompress_buffer! if compressed?
42
+
43
+ @bit_count = ((@buffer[8].ord & 0xff) >> 3)
44
+ end
45
+
46
+ def parse_packed_bits
47
+ PackedBitObject.from_packed_bits(@buffer, 8, 5, @bit_count) do |pbo|
48
+
49
+ PackedBitObject.from_packed_bits(@buffer, pbo.nextByteIndex, pbo.nextBitIndex, @bit_count) do |pbo2|
50
+ @xmax = pbo2.value
51
+
52
+ PackedBitObject.from_packed_bits(@buffer, pbo2.nextByteIndex, pbo2.nextBitIndex, @bit_count) do |pbo3|
53
+
54
+ PackedBitObject.from_packed_bits(@buffer, pbo3.nextByteIndex, pbo3.nextBitIndex, @bit_count) do |pbo4|
55
+ @ymax = pbo4.value
56
+ @width = Conversions::Pixels.from_twips @xmax
57
+ @height = Conversions::Pixels.from_twips @ymax
58
+
59
+ byte_pointer = pbo4.nextByteIndex + 2
60
+
61
+ @frame_rate = @buffer[byte_pointer].ord
62
+ byte_pointer += 1
63
+
64
+ fc1 = @buffer[byte_pointer].ord & 0xFF
65
+ byte_pointer += 1
66
+
67
+ fc2 = @buffer[byte_pointer].ord & 0xFF
68
+ byte_pointer += 1
69
+
70
+ @frame_count = (fc2 << 8) + fc1
71
+ byte_pointer+=2
72
+
73
+ @avm_version = ((@buffer[byte_pointer].ord & 0x08) == 0) ? "AVM1" : "AVM2"
74
+ end #pbo4
75
+ end #pbo3
76
+ end #pbo2
77
+ end #pbo
78
+ end
79
+
80
+ def get_swf_buffer_and_size
81
+ size = 0
82
+
83
+ buffer = File.open(@file,"rb") do |file|
84
+ file.seek(4, IO::SEEK_CUR)
85
+ size = file.read(4).unpack("L")[0]
86
+
87
+ file.rewind
88
+ file.read
89
+ end
90
+
91
+ [buffer, size]
92
+ end
93
+
94
+ def swf?
95
+ @buffer[0,3] == 'FWS' || @buffer[0,3] == 'CWS'
96
+ end
97
+ end
data/lib/swf_file.rb ADDED
@@ -0,0 +1,20 @@
1
+ $:.unshift File.join(File.dirname(__FILE__), 'swf_file') unless $:.include? File.join(File.dirname(__FILE__), 'swf_file')
2
+
3
+ require 'zlib'
4
+ require 'parser'
5
+ require 'compression'
6
+ require 'conversions'
7
+ require 'packed_bit_object'
8
+ require 'swf_header'
9
+
10
+ class SwfFile
11
+ def initialize(swf_path)
12
+ raise RuntimeError, "SWF file not found.", caller unless File.exists?(swf_path)
13
+ end
14
+
15
+ def self.header(swf_path)
16
+ raise RuntimeError, "SWF file not found.", caller unless File.exists?(swf_path)
17
+
18
+ SwfHeader.new(swf_path)
19
+ end
20
+ end
@@ -0,0 +1,11 @@
1
+ $:.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
2
+
3
+ require 'test/unit'
4
+ require 'shoulda'
5
+ #require 'swfheader'
6
+ require 'ruby-debug'
7
+ require 'swf_file'
8
+
9
+ def fixture_path(filename)
10
+ File.join(File.dirname(__FILE__), '..', 'fixtures', filename)
11
+ end
@@ -0,0 +1,99 @@
1
+ require_relative '../test_helper'
2
+
3
+ class SwfFileTest < Test::Unit::TestCase
4
+
5
+ context "SwfFile" do
6
+ context "Initialization" do
7
+ should "not be initializable without an SWF file path" do
8
+ assert_raise(ArgumentError) { SwfFile.new }
9
+ end
10
+
11
+ should "raise an error if an invalid path is provided" do
12
+ assert_raise(RuntimeError) { SwfFile.new "/path_to_imaginary_file" }
13
+ end
14
+ end # Initialization context
15
+
16
+ context "class method header" do
17
+ should "raise an error when not provided with an SWF" do
18
+ assert_raise(RuntimeError) { SwfFile.header fixture_path('smallgoat.jpg') }
19
+ end
20
+
21
+ setup do
22
+ @header = SwfFile.header fixture_path('clicktag.swf')
23
+ end
24
+
25
+ should "return an instance of SwfHeader" do
26
+ assert_equal SwfHeader, @header.class
27
+ end
28
+
29
+ should "indicate the file's size" do
30
+ assert_equal 4156, @header.size
31
+ end
32
+
33
+ should "state if the swf was originally compressed" do
34
+ assert @header.compressed?
35
+ refute SwfFile.header(fixture_path('clicktag-decompressed.swf')).compressed?
36
+ end
37
+
38
+ should "not make available private compression module methods" do
39
+ %w{ :buffer_compressed? :strip_buffer_header :decompress_buffer! }.each do |method|
40
+ refute @header.respond_to?(method)
41
+ end
42
+ end
43
+
44
+ should "state if its buffer is currently compressed" do
45
+ assert @header.compressed?
46
+ refute @header.compressed?(false)
47
+ end
48
+
49
+ should "have the version" do
50
+ assert_equal 8, @header.version
51
+ end
52
+
53
+ should "have the bit count" do
54
+ assert_equal 15, @header.bit_count
55
+ end
56
+
57
+ should "have the xmax and ymax values" do
58
+ assert_equal 9360, @header.xmax
59
+ assert_equal 1200, @header.ymax
60
+ end
61
+
62
+ should "have the width and height values" do
63
+ assert_equal 468, @header.width
64
+ assert_equal 60, @header.height
65
+ end
66
+
67
+ should "have the frame rate and frame count" do
68
+ assert_equal 24, @header.frame_rate
69
+ assert_equal 1, @header.frame_count
70
+ end
71
+
72
+ should "include the duration of the swf file" do
73
+ assert_equal 42, @header.duration
74
+ end
75
+
76
+ should "contain the avm version" do
77
+ assert_equal 'AVM1', @header.avm_version
78
+ end
79
+
80
+ should "include the swf signature" do
81
+ assert_equal 'CWS', @header.signature
82
+ end
83
+
84
+ should "output basing information when to_s is invoked" do
85
+ assert @header.to_s =~ /.+clicktag.swf\s\d+x\d+\s\d\dfps/
86
+ end
87
+
88
+ should "be have a hash converter" do
89
+ assert_equal Hash, @header.to_hash.class
90
+ end
91
+
92
+ should "have the same output for the instance methods inspect and to_hash" do
93
+ assert_equal @header.to_hash, @header.inspect
94
+ end
95
+
96
+ end # SWF operations context
97
+
98
+ end # SwfFile context
99
+ end # SwfFileTest
metadata ADDED
@@ -0,0 +1,81 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: swf_file
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 1
8
+ - 0
9
+ version: 0.1.0
10
+ platform: ruby
11
+ authors:
12
+ - DBA
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2010-05-06 00:00:00 +01:00
18
+ default_executable:
19
+ dependencies: []
20
+
21
+ description: Based on the swfutil lib, by Dennis Zhuang, the SWF File is lightweight gem to read swf file headers from within a Ruby application. This gem is fully written in Ruby and is compatible with Ruby v1.9.x
22
+ email: dba@gnomeslab.com
23
+ executables: []
24
+
25
+ extensions: []
26
+
27
+ extra_rdoc_files:
28
+ - LICENSE
29
+ - README
30
+ files:
31
+ - .gitignore
32
+ - LICENSE
33
+ - README
34
+ - Rakefile
35
+ - VERSION
36
+ - fixtures/clicktag-decompressed.swf
37
+ - fixtures/clicktag.swf
38
+ - fixtures/smallgoat.jpg
39
+ - lib/swf_file.rb
40
+ - lib/swf_file/compression.rb
41
+ - lib/swf_file/conversions.rb
42
+ - lib/swf_file/packed_bit_object.rb
43
+ - lib/swf_file/parser.rb
44
+ - lib/swf_file/swf_header.rb
45
+ - test/test_helper.rb
46
+ - test/unit/swf_file_test.rb
47
+ has_rdoc: true
48
+ homepage: http://github.com/DBA/swf_file
49
+ licenses: []
50
+
51
+ post_install_message:
52
+ rdoc_options:
53
+ - --charset=UTF-8
54
+ require_paths:
55
+ - lib
56
+ required_ruby_version: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ segments:
62
+ - 0
63
+ version: "0"
64
+ required_rubygems_version: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ">="
68
+ - !ruby/object:Gem::Version
69
+ segments:
70
+ - 0
71
+ version: "0"
72
+ requirements: []
73
+
74
+ rubyforge_project:
75
+ rubygems_version: 1.3.7
76
+ signing_key:
77
+ specification_version: 3
78
+ summary: SWF File is lightweight gem to read swf file headers from within a Ruby application
79
+ test_files:
80
+ - test/test_helper.rb
81
+ - test/unit/swf_file_test.rb