apetag 1.1.1 → 1.1.2
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/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:
|