swf_file 0.1.0 → 1.0.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/{README → README.rdoc} +20 -4
- data/VERSION +1 -1
- data/lib/swf_file/assertions.rb +10 -0
- data/lib/swf_file/compression.rb +1 -1
- data/lib/swf_file/conversions.rb +19 -17
- data/lib/swf_file/packed_bit_object.rb +25 -32
- data/lib/swf_file/parser.rb +46 -0
- data/lib/swf_file/swf_header.rb +7 -64
- data/lib/swf_file.rb +19 -3
- data/swf_file.gemspec +59 -0
- data/test/test_helper.rb +1 -1
- data/test/unit/swf_file_test.rb +15 -6
- metadata +7 -5
data/{README → README.rdoc}
RENAMED
@@ -1,4 +1,4 @@
|
|
1
|
-
|
1
|
+
=swf_file
|
2
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
3
|
|
4
4
|
==Ruby compatibility
|
@@ -14,7 +14,23 @@
|
|
14
14
|
Please refer to the LICENSE file.
|
15
15
|
|
16
16
|
==Example
|
17
|
-
|
17
|
+
swf = SwfFile.header 'clicktag.swf' # load the file
|
18
|
+
|
19
|
+
# Access the various header options. Please check the unit tests for more usage examples.
|
20
|
+
puts swf.size
|
21
|
+
puts swf.compressed?
|
22
|
+
puts swf.version
|
23
|
+
puts swf.bit_count
|
24
|
+
puts swf.xmax
|
25
|
+
puts swf.ymax
|
26
|
+
puts swf.width # In pixels
|
27
|
+
puts swf.height # In pixels
|
28
|
+
puts swf.frame_rate
|
29
|
+
puts swf.frame_count
|
30
|
+
puts swf.duration # In milliseconds
|
31
|
+
puts swf.avm_version
|
32
|
+
puts swf.signature
|
33
|
+
|
18
34
|
|
19
35
|
==Issues, improvements, feedback an suggestions
|
20
36
|
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.
|
@@ -23,5 +39,5 @@
|
|
23
39
|
|
24
40
|
==Pending
|
25
41
|
* Cleanup the class PackedBitObject, which still suffers from the pure import from SwfUtil
|
26
|
-
*
|
27
|
-
*
|
42
|
+
* Docs
|
43
|
+
* Modularize SwfHeader a bit more
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
|
1
|
+
1.0.0
|
data/lib/swf_file/compression.rb
CHANGED
data/lib/swf_file/conversions.rb
CHANGED
@@ -1,4 +1,23 @@
|
|
1
1
|
module Conversions
|
2
|
+
def to_s
|
3
|
+
"#{@file} #{@width}x#{@height} #{@frame_rate}fps"
|
4
|
+
end
|
5
|
+
|
6
|
+
def to_hash
|
7
|
+
{ :file => @file,
|
8
|
+
:signature => @signature,
|
9
|
+
:version => @version,
|
10
|
+
:avm_version => @avm_version,
|
11
|
+
:size => @size,
|
12
|
+
:bit_count => @bit_count,
|
13
|
+
:xmax => @xmax,
|
14
|
+
:ymax => @ymax,
|
15
|
+
:width => @width,
|
16
|
+
:height => @height,
|
17
|
+
:frame_rate => @frame_rate,
|
18
|
+
:frame_count => @frame_count }
|
19
|
+
end
|
20
|
+
|
2
21
|
module Twips
|
3
22
|
def self.from_pixels(pixels)
|
4
23
|
pixels * 20
|
@@ -10,21 +29,4 @@ module Conversions
|
|
10
29
|
twips / 20
|
11
30
|
end
|
12
31
|
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
32
|
end
|
@@ -1,54 +1,47 @@
|
|
1
|
-
# TODO: Needs refactoring & cleanup
|
2
|
-
|
3
1
|
class PackedBitObject
|
4
2
|
attr_accessor :bitIndex, :byteIndex, :value, :nextBitIndex, :nextByteIndex, :nextByteBoundary
|
5
3
|
|
6
|
-
def initialize(bitMarker,byteMarker,decimalValue)
|
7
|
-
@bitIndex = bitMarker
|
8
|
-
@byteIndex
|
9
|
-
@value
|
10
|
-
|
11
|
-
if
|
12
|
-
@nextBitIndex+=1
|
13
|
-
@nextByteIndex
|
14
|
-
@nextByteBoundary =
|
4
|
+
def initialize(bitMarker, byteMarker, decimalValue)
|
5
|
+
@nextBitIndex = @bitIndex = bitMarker
|
6
|
+
@byteIndex = byteMarker
|
7
|
+
@value = decimalValue
|
8
|
+
|
9
|
+
if bitMarker <= 7
|
10
|
+
@nextBitIndex += 1
|
11
|
+
@nextByteIndex = byteMarker
|
12
|
+
@nextByteBoundary = byteMarker += 1
|
15
13
|
else
|
16
|
-
@nextBitIndex
|
17
|
-
@nextByteIndex+=1
|
14
|
+
@nextBitIndex = 0
|
15
|
+
@nextByteIndex +=1
|
18
16
|
@nextByteBoundary = @nextByteIndex;
|
19
17
|
end
|
20
18
|
end
|
21
19
|
|
22
20
|
def self.from_packed_bits(bytes, byte_marker, bit_marker, length)
|
23
|
-
total = 0
|
24
|
-
shift
|
25
|
-
|
26
|
-
|
27
|
-
byte_index = byte_marker
|
21
|
+
counter = total = 0
|
22
|
+
shift = 7 - bit_marker
|
23
|
+
bit_index = bit_marker
|
24
|
+
byte_index = byte_marker
|
28
25
|
|
29
|
-
while counter<length
|
26
|
+
while counter < length
|
30
27
|
(bit_marker...8).each do |i|
|
31
|
-
bit
|
32
|
-
total
|
28
|
+
bit = ((bytes[byte_marker].ord & 0xff ) >> shift) & 1
|
29
|
+
total = (total << 1) + bit
|
33
30
|
bit_index = i
|
34
|
-
shift-=1
|
35
|
-
counter+=1
|
31
|
+
shift -= 1
|
32
|
+
counter += 1
|
36
33
|
|
37
|
-
if counter==length
|
38
|
-
break
|
39
|
-
end
|
34
|
+
break if counter == length
|
40
35
|
end
|
41
36
|
|
42
|
-
byte_index
|
43
|
-
byte_marker+=1
|
44
|
-
bit_marker
|
45
|
-
shift
|
37
|
+
byte_index = byte_marker
|
38
|
+
byte_marker +=1
|
39
|
+
bit_marker = 0
|
40
|
+
shift = 7
|
46
41
|
end
|
47
42
|
|
48
43
|
pbo = PackedBitObject.new(bit_index, byte_index, total)
|
49
|
-
|
50
44
|
yield pbo if block_given?
|
51
|
-
|
52
45
|
pbo
|
53
46
|
end
|
54
47
|
end
|
data/lib/swf_file/parser.rb
CHANGED
@@ -1,2 +1,48 @@
|
|
1
1
|
module Parser
|
2
|
+
private
|
3
|
+
def parse_header
|
4
|
+
@buffer, @size = get_swf_buffer_and_size
|
5
|
+
raise RuntimeError, "The provided file does not appear to be an SWF", caller unless swf?
|
6
|
+
|
7
|
+
@signature = @buffer[0,3]
|
8
|
+
@version = @buffer[3].ord
|
9
|
+
|
10
|
+
decompress_buffer! if compressed?
|
11
|
+
|
12
|
+
@bit_count = ((@buffer[8].ord & 0xff) >> 3)
|
13
|
+
end
|
14
|
+
|
15
|
+
def parse_packed_bits
|
16
|
+
PackedBitObject.from_packed_bits(@buffer, 8, 5, @bit_count) do |pbo|
|
17
|
+
|
18
|
+
PackedBitObject.from_packed_bits(@buffer, pbo.nextByteIndex, pbo.nextBitIndex, @bit_count) do |pbo2|
|
19
|
+
@xmax = pbo2.value
|
20
|
+
|
21
|
+
PackedBitObject.from_packed_bits(@buffer, pbo2.nextByteIndex, pbo2.nextBitIndex, @bit_count) do |pbo3|
|
22
|
+
|
23
|
+
PackedBitObject.from_packed_bits(@buffer, pbo3.nextByteIndex, pbo3.nextBitIndex, @bit_count) do |pbo4|
|
24
|
+
@ymax = pbo4.value
|
25
|
+
@width = Conversions::Pixels.from_twips @xmax
|
26
|
+
@height = Conversions::Pixels.from_twips @ymax
|
27
|
+
|
28
|
+
byte_pointer = pbo4.nextByteIndex + 2
|
29
|
+
|
30
|
+
@frame_rate = @buffer[byte_pointer].ord
|
31
|
+
byte_pointer += 1
|
32
|
+
|
33
|
+
fc1 = @buffer[byte_pointer].ord & 0xFF
|
34
|
+
byte_pointer += 1
|
35
|
+
|
36
|
+
fc2 = @buffer[byte_pointer].ord & 0xFF
|
37
|
+
byte_pointer += 1
|
38
|
+
|
39
|
+
@frame_count = (fc2 << 8) + fc1
|
40
|
+
byte_pointer+=2
|
41
|
+
|
42
|
+
@avm_version = ((@buffer[byte_pointer].ord & 0x08) == 0) ? "AVM1" : "AVM2"
|
43
|
+
end #pbo4
|
44
|
+
end #pbo3
|
45
|
+
end #pbo2
|
46
|
+
end #pbo
|
47
|
+
end
|
2
48
|
end
|
data/lib/swf_file/swf_header.rb
CHANGED
@@ -1,5 +1,8 @@
|
|
1
1
|
class SwfHeader
|
2
|
+
include Parser
|
2
3
|
include Compression
|
4
|
+
include Conversions
|
5
|
+
include Assertions
|
3
6
|
|
4
7
|
attr_reader :file, :signature, :version, :avm_version, :size, :bit_count,
|
5
8
|
:xmax, :ymax, :width, :height,
|
@@ -10,73 +13,17 @@ class SwfHeader
|
|
10
13
|
parse_header
|
11
14
|
parse_packed_bits
|
12
15
|
end
|
13
|
-
|
14
|
-
def compressed?(memoize_result = true)
|
15
|
-
buffer_compressed?(memoize_result)
|
16
|
-
end
|
17
|
-
|
16
|
+
|
18
17
|
# Returns the duration in milliseconds
|
18
|
+
# The formula used in this method used to be +((@frame_count / @frame_rate.to_f).round(5) * 1000).round+.
|
19
|
+
# This however, was not compatible with ruby 1.8, thus reverted to its current form.
|
19
20
|
def duration
|
20
|
-
((@frame_count / @frame_rate.to_f).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
|
21
|
+
((@frame_count / @frame_rate.to_f * 10**5).round.to_f / 10**5 * 1000).round
|
29
22
|
end
|
30
23
|
|
31
24
|
alias :inspect :to_hash
|
32
25
|
|
33
26
|
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
27
|
def get_swf_buffer_and_size
|
81
28
|
size = 0
|
82
29
|
|
@@ -90,8 +37,4 @@ class SwfHeader
|
|
90
37
|
|
91
38
|
[buffer, size]
|
92
39
|
end
|
93
|
-
|
94
|
-
def swf?
|
95
|
-
@buffer[0,3] == 'FWS' || @buffer[0,3] == 'CWS'
|
96
|
-
end
|
97
40
|
end
|
data/lib/swf_file.rb
CHANGED
@@ -4,17 +4,33 @@ require 'zlib'
|
|
4
4
|
require 'parser'
|
5
5
|
require 'compression'
|
6
6
|
require 'conversions'
|
7
|
+
require 'assertions'
|
7
8
|
require 'packed_bit_object'
|
8
9
|
require 'swf_header'
|
9
10
|
|
10
11
|
class SwfFile
|
11
|
-
|
12
|
+
# Class methods
|
13
|
+
def self.header(swf_path)
|
12
14
|
raise RuntimeError, "SWF file not found.", caller unless File.exists?(swf_path)
|
15
|
+
|
16
|
+
header = SwfHeader.new(swf_path)
|
17
|
+
yield(header) if block_given?
|
18
|
+
header
|
13
19
|
end
|
14
20
|
|
15
|
-
|
21
|
+
# Instance methods
|
22
|
+
def initialize(swf_path)
|
16
23
|
raise RuntimeError, "SWF file not found.", caller unless File.exists?(swf_path)
|
17
24
|
|
18
|
-
SwfHeader.new(swf_path)
|
25
|
+
@header = SwfHeader.new(swf_path)
|
26
|
+
end
|
27
|
+
|
28
|
+
def header
|
29
|
+
yield(@header) if block_given?
|
30
|
+
@header
|
31
|
+
end
|
32
|
+
|
33
|
+
def compressed?
|
34
|
+
@header.compressed?
|
19
35
|
end
|
20
36
|
end
|
data/swf_file.gemspec
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{swf_file}
|
8
|
+
s.version = "1.0.0"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["DBA"]
|
12
|
+
s.date = %q{2010-05-08}
|
13
|
+
s.description = %q{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}
|
14
|
+
s.email = %q{dba@gnomeslab.com}
|
15
|
+
s.extra_rdoc_files = [
|
16
|
+
"LICENSE",
|
17
|
+
"README.rdoc"
|
18
|
+
]
|
19
|
+
s.files = [
|
20
|
+
".gitignore",
|
21
|
+
"LICENSE",
|
22
|
+
"README.rdoc",
|
23
|
+
"Rakefile",
|
24
|
+
"VERSION",
|
25
|
+
"fixtures/clicktag-decompressed.swf",
|
26
|
+
"fixtures/clicktag.swf",
|
27
|
+
"fixtures/smallgoat.jpg",
|
28
|
+
"lib/swf_file.rb",
|
29
|
+
"lib/swf_file/assertions.rb",
|
30
|
+
"lib/swf_file/compression.rb",
|
31
|
+
"lib/swf_file/conversions.rb",
|
32
|
+
"lib/swf_file/packed_bit_object.rb",
|
33
|
+
"lib/swf_file/parser.rb",
|
34
|
+
"lib/swf_file/swf_header.rb",
|
35
|
+
"swf_file.gemspec",
|
36
|
+
"test/test_helper.rb",
|
37
|
+
"test/unit/swf_file_test.rb"
|
38
|
+
]
|
39
|
+
s.homepage = %q{http://github.com/DBA/swf_file}
|
40
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
41
|
+
s.require_paths = ["lib"]
|
42
|
+
s.rubygems_version = %q{1.3.7}
|
43
|
+
s.summary = %q{SWF File is lightweight gem to read swf file headers from within a Ruby application}
|
44
|
+
s.test_files = [
|
45
|
+
"test/test_helper.rb",
|
46
|
+
"test/unit/swf_file_test.rb"
|
47
|
+
]
|
48
|
+
|
49
|
+
if s.respond_to? :specification_version then
|
50
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
51
|
+
s.specification_version = 3
|
52
|
+
|
53
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
54
|
+
else
|
55
|
+
end
|
56
|
+
else
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
data/test/test_helper.rb
CHANGED
data/test/unit/swf_file_test.rb
CHANGED
@@ -1,9 +1,11 @@
|
|
1
|
-
|
1
|
+
$:.unshift(File.join(File.dirname(__FILE__), '../', '../', 'test'))
|
2
|
+
|
3
|
+
require 'test_helper'
|
2
4
|
|
3
5
|
class SwfFileTest < Test::Unit::TestCase
|
4
6
|
|
5
7
|
context "SwfFile" do
|
6
|
-
context "
|
8
|
+
context "instance methods" do
|
7
9
|
should "not be initializable without an SWF file path" do
|
8
10
|
assert_raise(ArgumentError) { SwfFile.new }
|
9
11
|
end
|
@@ -11,7 +13,14 @@ class SwfFileTest < Test::Unit::TestCase
|
|
11
13
|
should "raise an error if an invalid path is provided" do
|
12
14
|
assert_raise(RuntimeError) { SwfFile.new "/path_to_imaginary_file" }
|
13
15
|
end
|
14
|
-
|
16
|
+
|
17
|
+
should "return a header with the regular properties" do
|
18
|
+
swf = SwfFile.new fixture_path('clicktag.swf')
|
19
|
+
assert_equal SwfHeader, swf.header.class
|
20
|
+
assert_equal 4156, swf.header.size
|
21
|
+
assert_equal swf.compressed?, swf.header.compressed?
|
22
|
+
end
|
23
|
+
end # instance methods
|
15
24
|
|
16
25
|
context "class method header" do
|
17
26
|
should "raise an error when not provided with an SWF" do
|
@@ -32,18 +41,18 @@ class SwfFileTest < Test::Unit::TestCase
|
|
32
41
|
|
33
42
|
should "state if the swf was originally compressed" do
|
34
43
|
assert @header.compressed?
|
35
|
-
|
44
|
+
assert !SwfFile.header(fixture_path('clicktag-decompressed.swf')).compressed?
|
36
45
|
end
|
37
46
|
|
38
47
|
should "not make available private compression module methods" do
|
39
48
|
%w{ :buffer_compressed? :strip_buffer_header :decompress_buffer! }.each do |method|
|
40
|
-
|
49
|
+
assert !@header.respond_to?(method)
|
41
50
|
end
|
42
51
|
end
|
43
52
|
|
44
53
|
should "state if its buffer is currently compressed" do
|
45
54
|
assert @header.compressed?
|
46
|
-
|
55
|
+
assert !@header.compressed?(false)
|
47
56
|
end
|
48
57
|
|
49
58
|
should "have the version" do
|
metadata
CHANGED
@@ -3,10 +3,10 @@ name: swf_file
|
|
3
3
|
version: !ruby/object:Gem::Version
|
4
4
|
prerelease: false
|
5
5
|
segments:
|
6
|
-
- 0
|
7
6
|
- 1
|
8
7
|
- 0
|
9
|
-
|
8
|
+
- 0
|
9
|
+
version: 1.0.0
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- DBA
|
@@ -14,7 +14,7 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2010-05-
|
17
|
+
date: 2010-05-08 00:00:00 +01:00
|
18
18
|
default_executable:
|
19
19
|
dependencies: []
|
20
20
|
|
@@ -26,22 +26,24 @@ extensions: []
|
|
26
26
|
|
27
27
|
extra_rdoc_files:
|
28
28
|
- LICENSE
|
29
|
-
- README
|
29
|
+
- README.rdoc
|
30
30
|
files:
|
31
31
|
- .gitignore
|
32
32
|
- LICENSE
|
33
|
-
- README
|
33
|
+
- README.rdoc
|
34
34
|
- Rakefile
|
35
35
|
- VERSION
|
36
36
|
- fixtures/clicktag-decompressed.swf
|
37
37
|
- fixtures/clicktag.swf
|
38
38
|
- fixtures/smallgoat.jpg
|
39
39
|
- lib/swf_file.rb
|
40
|
+
- lib/swf_file/assertions.rb
|
40
41
|
- lib/swf_file/compression.rb
|
41
42
|
- lib/swf_file/conversions.rb
|
42
43
|
- lib/swf_file/packed_bit_object.rb
|
43
44
|
- lib/swf_file/parser.rb
|
44
45
|
- lib/swf_file/swf_header.rb
|
46
|
+
- swf_file.gemspec
|
45
47
|
- test/test_helper.rb
|
46
48
|
- test/unit/swf_file_test.rb
|
47
49
|
has_rdoc: true
|