taglib-ruby 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +11 -0
- data/Gemfile.lock +25 -0
- data/LICENSE.txt +20 -0
- data/README.md +109 -0
- data/Rakefile +63 -0
- data/ext/Rakefile +32 -0
- data/ext/extconf_common.rb +18 -0
- data/ext/taglib_base/extconf.rb +4 -0
- data/ext/taglib_base/includes.i +41 -0
- data/ext/taglib_base/taglib_base.i +83 -0
- data/ext/taglib_base/taglib_base_wrap.cxx +7069 -0
- data/ext/taglib_id3v2/extconf.rb +4 -0
- data/ext/taglib_id3v2/taglib_id3v2.i +111 -0
- data/ext/taglib_id3v2/taglib_id3v2_wrap.cxx +16496 -0
- data/ext/taglib_mpeg/extconf.rb +4 -0
- data/ext/taglib_mpeg/taglib_mpeg.i +60 -0
- data/ext/taglib_mpeg/taglib_mpeg_wrap.cxx +5533 -0
- data/ext/valgrind-suppressions.txt +170 -0
- data/lib/taglib.rb +3 -0
- data/lib/taglib/base.rb +1 -0
- data/lib/taglib/id3v2.rb +42 -0
- data/lib/taglib/mpeg.rb +1 -0
- data/lib/taglib/version.rb +10 -0
- data/test/data/globe_east_540.jpg +0 -0
- data/test/data/sample.mp3 +0 -0
- data/test/data/unicode.mp3 +0 -0
- data/test/helper.rb +10 -0
- data/test/test_id3v2_frames.rb +93 -0
- data/test/test_id3v2_memory.rb +54 -0
- data/test/test_id3v2_tag.rb +31 -0
- data/test/test_id3v2_unicode.rb +42 -0
- data/test/test_id3v2_write.rb +95 -0
- data/test/test_tag.rb +21 -0
- metadata +227 -0
@@ -0,0 +1,170 @@
|
|
1
|
+
{
|
2
|
+
taglib_base SWIG_InitializeModule
|
3
|
+
exp-ptrcheck:SorG
|
4
|
+
fun:Init_taglib_base
|
5
|
+
fun:dln_load
|
6
|
+
}
|
7
|
+
{
|
8
|
+
taglib_id3v2 SWIG_InitializeModule
|
9
|
+
exp-ptrcheck:SorG
|
10
|
+
fun:Init_taglib_id3v2
|
11
|
+
fun:dln_load
|
12
|
+
}
|
13
|
+
{
|
14
|
+
taglib_mpeg SWIG_InitializeModule
|
15
|
+
exp-ptrcheck:SorG
|
16
|
+
fun:Init_taglib_mpeg
|
17
|
+
fun:dln_load
|
18
|
+
}
|
19
|
+
# Ruby 1.9 VM supressions
|
20
|
+
{
|
21
|
+
r1
|
22
|
+
Memcheck:Cond
|
23
|
+
fun:gc_mark
|
24
|
+
}
|
25
|
+
{
|
26
|
+
r2
|
27
|
+
Memcheck:Cond
|
28
|
+
fun:gc_mark_children
|
29
|
+
}
|
30
|
+
{
|
31
|
+
r3
|
32
|
+
Memcheck:Cond
|
33
|
+
fun:mark_current_machine_context
|
34
|
+
}
|
35
|
+
{
|
36
|
+
r4
|
37
|
+
Memcheck:Value8
|
38
|
+
fun:gc_mark
|
39
|
+
}
|
40
|
+
{
|
41
|
+
r5
|
42
|
+
Memcheck:Value8
|
43
|
+
fun:gc_mark_children
|
44
|
+
}
|
45
|
+
{
|
46
|
+
r6
|
47
|
+
Memcheck:Value8
|
48
|
+
fun:mark_current_machine_context
|
49
|
+
}
|
50
|
+
{
|
51
|
+
r7
|
52
|
+
Memcheck:Value8
|
53
|
+
fun:vm_exec_core
|
54
|
+
}
|
55
|
+
{
|
56
|
+
r8
|
57
|
+
Memcheck:Value4
|
58
|
+
fun:find_derivation
|
59
|
+
}
|
60
|
+
{
|
61
|
+
r9
|
62
|
+
Memcheck:Value8
|
63
|
+
fun:__gconv_read_conf
|
64
|
+
}
|
65
|
+
{
|
66
|
+
r10
|
67
|
+
Memcheck:Leak
|
68
|
+
fun:malloc
|
69
|
+
fun:vm_xmalloc
|
70
|
+
fun:ruby_strdup
|
71
|
+
}
|
72
|
+
{
|
73
|
+
r11
|
74
|
+
Memcheck:Leak
|
75
|
+
fun:malloc
|
76
|
+
fun:vm_xmalloc
|
77
|
+
fun:rb_include_module
|
78
|
+
}
|
79
|
+
{
|
80
|
+
r12
|
81
|
+
Memcheck:Leak
|
82
|
+
...
|
83
|
+
fun:ruby_init
|
84
|
+
fun:main
|
85
|
+
}
|
86
|
+
{
|
87
|
+
r20
|
88
|
+
exp-ptrcheck:SorG
|
89
|
+
fun:insert_module
|
90
|
+
}
|
91
|
+
{
|
92
|
+
r21
|
93
|
+
exp-ptrcheck:SorG
|
94
|
+
fun:find_derivation
|
95
|
+
}
|
96
|
+
{
|
97
|
+
r22
|
98
|
+
exp-ptrcheck:SorG
|
99
|
+
fun:vm_exec_core
|
100
|
+
}
|
101
|
+
{
|
102
|
+
r23
|
103
|
+
exp-ptrcheck:SorG
|
104
|
+
fun:__gconv_read_conf
|
105
|
+
}
|
106
|
+
{
|
107
|
+
r24
|
108
|
+
exp-ptrcheck:SorG
|
109
|
+
fun:mark_current_machine_context
|
110
|
+
}
|
111
|
+
# Ruby 1.8 suppressions
|
112
|
+
{
|
113
|
+
r18_1
|
114
|
+
Memcheck:Cond
|
115
|
+
fun:mark_locations_array
|
116
|
+
...
|
117
|
+
fun:yycompile
|
118
|
+
}
|
119
|
+
{
|
120
|
+
r18_2
|
121
|
+
Memcheck:Cond
|
122
|
+
fun:mark_locations_array
|
123
|
+
...
|
124
|
+
fun:rb_eval
|
125
|
+
}
|
126
|
+
{
|
127
|
+
r18_3
|
128
|
+
Memcheck:Leak
|
129
|
+
fun:malloc
|
130
|
+
fun:ruby_xmalloc
|
131
|
+
fun:scope_dup
|
132
|
+
}
|
133
|
+
{
|
134
|
+
r18_4
|
135
|
+
Memcheck:Leak
|
136
|
+
fun:malloc
|
137
|
+
...
|
138
|
+
fun:yycompile
|
139
|
+
}
|
140
|
+
{
|
141
|
+
r18_5
|
142
|
+
exp-ptrcheck:SorG
|
143
|
+
fun:mark_locations_array
|
144
|
+
fun:garbage_collect
|
145
|
+
...
|
146
|
+
fun:yycompile
|
147
|
+
}
|
148
|
+
{
|
149
|
+
r18_6
|
150
|
+
exp-ptrcheck:Heap
|
151
|
+
...
|
152
|
+
fun:rb_intern
|
153
|
+
fun:rb_str_intern
|
154
|
+
fun:rb_to_id
|
155
|
+
fun:rb_mod_alias_method
|
156
|
+
}
|
157
|
+
{
|
158
|
+
r18_7
|
159
|
+
exp-ptrcheck:SorG
|
160
|
+
fun:ruby_yyparse
|
161
|
+
fun:yycompile
|
162
|
+
}
|
163
|
+
{
|
164
|
+
r18_8
|
165
|
+
exp-ptrcheck:SorG
|
166
|
+
fun:ruby_re_compile_pattern
|
167
|
+
fun:rb_reg_initialize
|
168
|
+
...
|
169
|
+
fun:rb_class_new_instance
|
170
|
+
}
|
data/lib/taglib.rb
ADDED
data/lib/taglib/base.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'taglib_base'
|
data/lib/taglib/id3v2.rb
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'taglib_id3v2'
|
2
|
+
|
3
|
+
module TagLib
|
4
|
+
module ID3v2
|
5
|
+
class FrameList
|
6
|
+
include Enumerable
|
7
|
+
|
8
|
+
def each
|
9
|
+
it = self.begin
|
10
|
+
it_end = self.end
|
11
|
+
while it != it_end
|
12
|
+
frame = it.value
|
13
|
+
casted_frame = frame.cast
|
14
|
+
yield casted_frame
|
15
|
+
it = it.next
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
class Frame
|
20
|
+
def to_s
|
21
|
+
to_string
|
22
|
+
end
|
23
|
+
def cast
|
24
|
+
case frame_id
|
25
|
+
when "APIC" then to_attached_picture_frame
|
26
|
+
when "COMM" then to_comments_frame
|
27
|
+
when "GEOB" then to_general_encapsulated_object_frame
|
28
|
+
when "POPM" then to_popularimeter_frame
|
29
|
+
when "PRIV" then to_private_frame
|
30
|
+
when "RVAD" then to_relative_volume_frame
|
31
|
+
when "TXXX" then to_user_text_identification_frame
|
32
|
+
when /T.../ then to_text_identification_frame
|
33
|
+
when "UFID" then to_unique_file_identifier_frame
|
34
|
+
when "USLT" then to_unsynchronized_lyrics_frame
|
35
|
+
when "WXXX" then to_user_url_link_frame
|
36
|
+
when /W.../ then to_url_link_frame
|
37
|
+
else self
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
data/lib/taglib/mpeg.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'taglib_mpeg'
|
Binary file
|
Binary file
|
Binary file
|
data/test/helper.rb
ADDED
@@ -0,0 +1,93 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
class TestID3v2Frames < Test::Unit::TestCase
|
4
|
+
context "The sample.mp3 file's frames" do
|
5
|
+
setup do
|
6
|
+
read_properties = false
|
7
|
+
# It's important that file is an instance variable, otherwise the
|
8
|
+
# tag would get garbage collected along with the file, even if tag
|
9
|
+
# itself would still be reachable. The reason is because
|
10
|
+
# TagLib::MPEG::File owns the TagLib::ID3v2::Tag and automatically
|
11
|
+
# deletes it in its destructor.
|
12
|
+
@file = TagLib::MPEG::File.new("test/data/sample.mp3", read_properties)
|
13
|
+
picture_file = File.open("test/data/globe_east_540.jpg", "rb") do |f|
|
14
|
+
@picture_data = f.read
|
15
|
+
end
|
16
|
+
@tag = @file.id3v2_tag
|
17
|
+
@frames = @tag.frame_list
|
18
|
+
end
|
19
|
+
|
20
|
+
should "be complete" do
|
21
|
+
assert_not_nil @frames
|
22
|
+
assert_equal 11, @frames.size
|
23
|
+
iterator = @frames.begin
|
24
|
+
frame = iterator.value
|
25
|
+
assert_equal "Dummy Title", frame.to_string
|
26
|
+
end
|
27
|
+
|
28
|
+
should "be enumerable" do
|
29
|
+
ids = @frames.collect{ |frame| frame.frame_id }
|
30
|
+
assert_equal ["TIT2", "TPE1", "TALB", "TRCK", "TDRC",
|
31
|
+
"COMM", "COMM", "TCON", "TXXX", "COMM", "APIC"], ids
|
32
|
+
end
|
33
|
+
|
34
|
+
should "be automatically converted" do
|
35
|
+
apic = @tag.frame_list('APIC').first
|
36
|
+
comm = @tag.frame_list('COMM').first
|
37
|
+
tit2 = @tag.frame_list('TIT2').first
|
38
|
+
assert_equal TagLib::ID3v2::AttachedPictureFrame, apic.class
|
39
|
+
assert_equal TagLib::ID3v2::CommentsFrame, comm.class
|
40
|
+
assert_equal TagLib::ID3v2::TextIdentificationFrame, tit2.class
|
41
|
+
end
|
42
|
+
|
43
|
+
context "APIC frame" do
|
44
|
+
setup do
|
45
|
+
@apic = @tag.frame_list('APIC').first
|
46
|
+
end
|
47
|
+
|
48
|
+
should "have a type" do
|
49
|
+
assert_equal TagLib::ID3v2::AttachedPictureFrame::FrontCover, @apic.type
|
50
|
+
end
|
51
|
+
|
52
|
+
should "have a description" do
|
53
|
+
assert_equal "Blue Marble", @apic.description
|
54
|
+
end
|
55
|
+
|
56
|
+
should "have a mime type" do
|
57
|
+
assert_equal "image/jpeg", @apic.mime_type
|
58
|
+
end
|
59
|
+
|
60
|
+
should "have picture bytes" do
|
61
|
+
assert_equal 61649, @apic.picture.size
|
62
|
+
if HAVE_ENCODING
|
63
|
+
assert_equal @picture_data.encoding, @apic.picture.encoding
|
64
|
+
end
|
65
|
+
assert_equal @picture_data, @apic.picture
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
context "TXXX frame" do
|
70
|
+
setup do
|
71
|
+
@txxx_frame = @tag.frame_list('TXXX').first
|
72
|
+
end
|
73
|
+
|
74
|
+
should "exist" do
|
75
|
+
assert_not_nil @txxx_frame
|
76
|
+
end
|
77
|
+
|
78
|
+
should "have to_s" do
|
79
|
+
expected = "[MusicBrainz Album Id] MusicBrainz Album Id 992dc19a-5631-40f5-b252-fbfedbc328a9"
|
80
|
+
assert_equal expected, @txxx_frame.to_s
|
81
|
+
end
|
82
|
+
|
83
|
+
should "be convertable to its concrete type" do
|
84
|
+
txxx = @txxx_frame.to_user_text_identification_frame
|
85
|
+
assert_equal TagLib::ID3v2::UserTextIdentificationFrame, txxx.class
|
86
|
+
end
|
87
|
+
|
88
|
+
should "have field_list" do
|
89
|
+
assert_equal ["MusicBrainz Album Id", "992dc19a-5631-40f5-b252-fbfedbc328a9"], @txxx_frame.field_list
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
class TestID3v2Memory < Test::Unit::TestCase
|
4
|
+
|
5
|
+
N = 1000
|
6
|
+
|
7
|
+
context "TagLib::ID3v2" do
|
8
|
+
setup do
|
9
|
+
@file = TagLib::MPEG::File.new("test/data/sample.mp3", false)
|
10
|
+
@tag = @file.id3v2_tag
|
11
|
+
@apic = @tag.frame_list("APIC").first
|
12
|
+
end
|
13
|
+
|
14
|
+
should "not corrupt memory with FrameList" do
|
15
|
+
N.times do
|
16
|
+
@tag.frame_list
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
should "not corrupt memory with ByteVector" do
|
21
|
+
data = nil
|
22
|
+
N.times do
|
23
|
+
data = @apic.picture
|
24
|
+
end
|
25
|
+
N.times do
|
26
|
+
@apic.picture = data
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
should "not corrupt memory with StringList" do
|
31
|
+
txxx = @tag.frame_list('TXXX').first
|
32
|
+
N.times do
|
33
|
+
txxx.field_list
|
34
|
+
end
|
35
|
+
N.times do
|
36
|
+
txxx.field_list = ["one", "two", "three"]
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
should "not segfault when tag is deleted along with file" do
|
41
|
+
@file = nil
|
42
|
+
begin
|
43
|
+
N.times do
|
44
|
+
GC.start
|
45
|
+
@tag.title
|
46
|
+
end
|
47
|
+
rescue => e
|
48
|
+
assert_equal "ObjectPreviouslyDeleted", e.class.to_s
|
49
|
+
else
|
50
|
+
raise "GC did not delete file, unsure if test was successful."
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
class TestID3v2Tag < Test::Unit::TestCase
|
4
|
+
context "The sample.mp3 file" do
|
5
|
+
setup do
|
6
|
+
read_properties = false
|
7
|
+
@file = TagLib::MPEG::File.new("test/data/sample.mp3", read_properties)
|
8
|
+
end
|
9
|
+
|
10
|
+
should "have an ID3v2 tag" do
|
11
|
+
assert_not_nil @file.id3v2_tag
|
12
|
+
end
|
13
|
+
|
14
|
+
context "tag" do
|
15
|
+
setup do
|
16
|
+
@tag = @file.id3v2_tag
|
17
|
+
end
|
18
|
+
|
19
|
+
should "have basic properties" do
|
20
|
+
assert_equal 'Dummy Title', @tag.title
|
21
|
+
assert_equal 'Dummy Artist', @tag.artist
|
22
|
+
assert_equal 'Dummy Album', @tag.album
|
23
|
+
assert_equal 'Dummy Comment', @tag.comment
|
24
|
+
assert_equal 'Pop', @tag.genre
|
25
|
+
assert_equal 2000, @tag.year
|
26
|
+
assert_equal 1, @tag.track
|
27
|
+
assert_equal false, @tag.empty?
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
class TestID3v2Unicode < Test::Unit::TestCase
|
4
|
+
context "The unicode.mp3 file" do
|
5
|
+
setup do
|
6
|
+
read_properties = false
|
7
|
+
@file = TagLib::MPEG::File.new("test/data/unicode.mp3", read_properties)
|
8
|
+
end
|
9
|
+
|
10
|
+
should "have an ID3v2 tag" do
|
11
|
+
assert_not_nil @file.id3v2_tag
|
12
|
+
end
|
13
|
+
|
14
|
+
if HAVE_ENCODING
|
15
|
+
context "tag" do
|
16
|
+
setup do
|
17
|
+
@tag = @file.id3v2_tag
|
18
|
+
end
|
19
|
+
|
20
|
+
should "return strings in the right encoding" do
|
21
|
+
assert_equal "UTF-8", @tag.title.encoding.to_s
|
22
|
+
end
|
23
|
+
|
24
|
+
should "convert strings to the right encoding" do
|
25
|
+
# Unicode Snowman in UTF-16
|
26
|
+
utf16_encoded = "\x26\x03"
|
27
|
+
utf16_encoded.force_encoding("UTF-16BE")
|
28
|
+
|
29
|
+
# It should be converted here
|
30
|
+
@tag.title = utf16_encoded
|
31
|
+
|
32
|
+
result = @tag.title
|
33
|
+
|
34
|
+
# In order for == to work, they have to be in the same
|
35
|
+
# encoding
|
36
|
+
utf8_encoded = utf16_encoded.encode("UTF-8")
|
37
|
+
assert_equal utf8_encoded, result
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|