swf_file 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +3 -0
- data/LICENSE +28 -0
- data/README +27 -0
- data/Rakefile +28 -0
- data/VERSION +1 -0
- data/fixtures/clicktag-decompressed.swf +0 -0
- data/fixtures/clicktag.swf +0 -0
- data/fixtures/smallgoat.jpg +0 -0
- data/lib/swf_file/compression.rb +25 -0
- data/lib/swf_file/conversions.rb +30 -0
- data/lib/swf_file/packed_bit_object.rb +54 -0
- data/lib/swf_file/parser.rb +2 -0
- data/lib/swf_file/swf_header.rb +97 -0
- data/lib/swf_file.rb +20 -0
- data/test/test_helper.rb +11 -0
- data/test/unit/swf_file_test.rb +99 -0
- metadata +81 -0
data/.gitignore
ADDED
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,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
|
data/test/test_helper.rb
ADDED
@@ -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
|