apetag 1.1.1 → 1.1.2
Sign up to get free protection for your applications and to get access to all the features.
- data/apetag.rb +11 -12
- data/test/test_apetag.rb +23 -6
- metadata +5 -5
data/apetag.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
-
# This library implements a APEv2
|
2
|
+
# This library implements a APEv2 reader/writer.
|
3
3
|
# If called from the command line, it prints out the contents of the APEv2 tag
|
4
4
|
# for the given filename arguments.
|
5
5
|
#
|
@@ -61,7 +61,6 @@
|
|
61
61
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
62
62
|
# SOFTWARE.
|
63
63
|
|
64
|
-
require 'set'
|
65
64
|
require 'cicphash'
|
66
65
|
|
67
66
|
# Error raised by the library
|
@@ -189,8 +188,8 @@ end
|
|
189
188
|
class ApeTag
|
190
189
|
MAX_SIZE = 8192
|
191
190
|
MAX_ITEM_COUNT = 64
|
192
|
-
HEADER_FLAGS = "\x00\x00\
|
193
|
-
FOOTER_FLAGS = "\x00\x00\
|
191
|
+
HEADER_FLAGS = "\x00\x00\xA0"
|
192
|
+
FOOTER_FLAGS = "\x00\x00\x80"
|
194
193
|
PREAMBLE = "APETAGEX\xD0\x07\x00\x00"
|
195
194
|
RECOMMENDED_KEYS = %w'Title Artist Album Year Comment Genre Track Subtitle
|
196
195
|
Publisher Conductor Composer Copyright Publicationright File EAN/UPC ISBN
|
@@ -249,8 +248,7 @@ class ApeTag
|
|
249
248
|
@check_id3 = check_id3.nil? ? @@check_id3 : check_id3
|
250
249
|
else
|
251
250
|
@filename = filename.to_s
|
252
|
-
@check_id3 = check_id3
|
253
|
-
@check_id3 = !MP3_RE.match(@filename).nil? if @check_id3.nil?
|
251
|
+
@check_id3 = check_id3.nil? ? !MP3_RE.match(@filename).nil? : check_id3
|
254
252
|
end
|
255
253
|
end
|
256
254
|
|
@@ -368,11 +366,12 @@ class ApeTag
|
|
368
366
|
end
|
369
367
|
file.seek(-32-id3.length, IO::SEEK_END)
|
370
368
|
tag_footer = file.read(32)
|
371
|
-
unless tag_footer[0...12] == PREAMBLE
|
369
|
+
unless tag_footer[0...12] == PREAMBLE
|
372
370
|
@has_tag = false
|
373
371
|
@tag_start = file_size - id3.length
|
374
372
|
return
|
375
373
|
end
|
374
|
+
raise ApeTagError, "Tag has bad footer flags" unless tag_footer[21...24] == FOOTER_FLAGS && (tag_footer[20...21] == "\x00" || tag_footer[20...21] == "\x01")
|
376
375
|
@tag_footer = tag_footer
|
377
376
|
@tag_size, @tag_item_count = tag_footer[12...20].unpack('VV')
|
378
377
|
@tag_size += 32
|
@@ -385,9 +384,9 @@ class ApeTag
|
|
385
384
|
@tag_start=file.pos
|
386
385
|
@tag_header=file.read(32)
|
387
386
|
@tag_data=file.read(tag_size-64)
|
388
|
-
raise ApeTagError, "Missing header" unless tag_header[0...12] == PREAMBLE && tag_header[
|
389
|
-
raise ApeTagError, "Header and footer size does match" unless tag_size == tag_header[12...16].unpack('V')[0] + 32
|
390
|
-
raise ApeTagError, "Header and footer item count does match" unless tag_item_count == tag_header[16...20].unpack('V')[0]
|
387
|
+
raise ApeTagError, "Missing header" unless tag_header[0...12] == PREAMBLE && tag_header[21...24] == HEADER_FLAGS && (tag_header[20...21] == "\x00" || tag_header[20...21] == "\x01")
|
388
|
+
raise ApeTagError, "Header and footer size does not match" unless tag_size == tag_header[12...16].unpack('V')[0] + 32
|
389
|
+
raise ApeTagError, "Header and footer item count does not match" unless tag_item_count == tag_header[16...20].unpack('V')[0]
|
391
390
|
@has_tag = true
|
392
391
|
end
|
393
392
|
|
@@ -428,8 +427,8 @@ class ApeTag
|
|
428
427
|
@tag_size = tag_data.length + 64
|
429
428
|
base_start = "#{PREAMBLE}#{[tag_size-32, tag_item_count].pack('VV')}"
|
430
429
|
base_end = "\0"*8
|
431
|
-
@tag_header = "#{base_start}#{HEADER_FLAGS}#{base_end}"
|
432
|
-
@tag_footer = "#{base_start}#{FOOTER_FLAGS}#{base_end}"
|
430
|
+
@tag_header = "#{base_start}\x00#{HEADER_FLAGS}#{base_end}"
|
431
|
+
@tag_footer = "#{base_start}\x00#{FOOTER_FLAGS}#{base_end}"
|
433
432
|
raise ApeTagError, "Updated tag has too many items (#{tag_item_count})" if tag_item_count > MAX_ITEM_COUNT
|
434
433
|
raise ApeTagError, "Updated tag too large (#{tag_size})" if tag_size > MAX_SIZE
|
435
434
|
end
|
data/test/test_apetag.rb
CHANGED
@@ -228,7 +228,7 @@ class ApeTagTest < Test::Unit::TestCase
|
|
228
228
|
assert_equal "XYZ", ai.string_value
|
229
229
|
|
230
230
|
# Test parsing of invalid UTF-8
|
231
|
-
data = "\012\0\0\0\
|
231
|
+
data = "\012\0\0\0\0\0\0\0BlaH\0BlAh\0XYZ\0\xff"
|
232
232
|
assert_raises(ApeTagError){ApeItem.parse(data, 0)}
|
233
233
|
end
|
234
234
|
|
@@ -237,6 +237,23 @@ class ApeTagTest < Test::Unit::TestCase
|
|
237
237
|
data = EMPTY_APE_TAG.dup
|
238
238
|
# Test default case OK
|
239
239
|
assert_nothing_raised{ApeTag.new(StringIO.new(data)).raw}
|
240
|
+
|
241
|
+
# Test read only tags work
|
242
|
+
data[20] = 1
|
243
|
+
assert_nothing_raised{ApeTag.new(StringIO.new(data)).raw}
|
244
|
+
|
245
|
+
# Test other flags values don't work
|
246
|
+
2.upto(255) do |i|
|
247
|
+
data[20] = i
|
248
|
+
assert_raises(ApeTagError){ApeTag.new(StringIO.new(data)).raw}
|
249
|
+
end
|
250
|
+
data[20] = 1
|
251
|
+
2.upto(255) do |i|
|
252
|
+
data[52] = i
|
253
|
+
assert_raises(ApeTagError){ApeTag.new(StringIO.new(data)).raw}
|
254
|
+
data[20] = i
|
255
|
+
assert_raises(ApeTagError){ApeTag.new(StringIO.new(data)).raw}
|
256
|
+
end
|
240
257
|
|
241
258
|
# Test footer size less than minimum size (32)
|
242
259
|
data[44] = 31
|
@@ -284,7 +301,7 @@ class ApeTagTest < Test::Unit::TestCase
|
|
284
301
|
|
285
302
|
# Test unmatched header and footer item count, footer size wrong
|
286
303
|
data = EXAMPLE_APE_TAG.dup
|
287
|
-
data[
|
304
|
+
data[208-16] -=1
|
288
305
|
assert_raises(ApeTagError){ApeTag.new(StringIO.new(data)).fields}
|
289
306
|
|
290
307
|
# Test missing/corrupt header
|
@@ -330,7 +347,7 @@ class ApeTagTest < Test::Unit::TestCase
|
|
330
347
|
data[192] += 2
|
331
348
|
assert_raises(ApeTagError){ApeTag.new(StringIO.new(data)).fields}
|
332
349
|
|
333
|
-
# Test updating works in case insensitive manner
|
350
|
+
# Test updating works in a case insensitive manner
|
334
351
|
assert_equal ['blah'], ApeTag.new(StringIO.new(EXAMPLE_APE_TAG.dup)).update{|x| x['album']='blah'}['ALBUM']
|
335
352
|
assert_equal ['blah'], ApeTag.new(StringIO.new(EXAMPLE_APE_TAG.dup)).update{|x| x['ALBUM']='blah'}['album']
|
336
353
|
assert_equal ['blah'], ApeTag.new(StringIO.new(EXAMPLE_APE_TAG.dup)).update{|x| x['ALbUM']='blah'}['albuM']
|
@@ -345,10 +362,10 @@ class ApeTagTest < Test::Unit::TestCase
|
|
345
362
|
# Test ID3v1.0 tag
|
346
363
|
assert_nothing_raised{ApeTag.new(StringIO.new(EXAMPLE_APE_TAG[0...-128] + EXAMPLE_APE_TAG[-128..-1].gsub("\0", " "))).update{|x| x}}
|
347
364
|
|
348
|
-
# Test updating with invalid value
|
365
|
+
# Test updating with an invalid value
|
349
366
|
assert_raises(ApeTagError){ApeTag.new(StringIO.new(EMPTY_APE_TAG.dup)).update{|x| x['Album']="\xfe"}}
|
350
367
|
|
351
|
-
# Test updating with invalid key
|
368
|
+
# Test updating with an invalid key
|
352
369
|
assert_raises(ApeTagError){ApeTag.new(StringIO.new(EMPTY_APE_TAG.dup)).update{|x| x['x']=""}}
|
353
370
|
|
354
371
|
# Test updating with too many items
|
@@ -358,7 +375,7 @@ class ApeTagTest < Test::Unit::TestCase
|
|
358
375
|
|
359
376
|
# Test updating with too large a tag
|
360
377
|
assert_raises(ApeTagError){ApeTag.new(StringIO.new(EMPTY_APE_TAG.dup)).update{|x| x['xx']=' '*8118}}
|
361
|
-
# Test updating with just enough tag
|
378
|
+
# Test updating with a just large enough tag
|
362
379
|
assert_nothing_raised{ApeTag.new(StringIO.new(EMPTY_APE_TAG.dup)).update{|x| x['xx']=' '*8117}}
|
363
380
|
end
|
364
381
|
|
metadata
CHANGED
@@ -1,16 +1,16 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
|
-
rubygems_version: 0.9.
|
2
|
+
rubygems_version: 0.9.4
|
3
3
|
specification_version: 1
|
4
4
|
name: apetag
|
5
5
|
version: !ruby/object:Gem::Version
|
6
|
-
version: 1.1.
|
7
|
-
date: 2007-
|
8
|
-
summary: APEv2 Tag
|
6
|
+
version: 1.1.2
|
7
|
+
date: 2007-11-07 00:00:00 -08:00
|
8
|
+
summary: APEv2 Tag Reader/Writer
|
9
9
|
require_paths:
|
10
10
|
- .
|
11
11
|
email: code@jeremyevans.net
|
12
12
|
homepage:
|
13
|
-
rubyforge_project:
|
13
|
+
rubyforge_project: apetag
|
14
14
|
description:
|
15
15
|
autorequire: apetag
|
16
16
|
default_executable:
|