apetag 1.1.2 → 1.1.3

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.
Files changed (3) hide show
  1. data/apetag.rb +13 -5
  2. data/test/test_apetag.rb +47 -40
  3. metadata +69 -40
data/apetag.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  #!/usr/bin/env ruby
2
+ # encoding: ascii
2
3
  # This library implements a APEv2 reader/writer.
3
4
  # If called from the command line, it prints out the contents of the APEv2 tag
4
5
  # for the given filename arguments.
@@ -35,9 +36,12 @@
35
36
  # If you find any bugs, would like additional documentation, or want to submit a
36
37
  # patch, please use Rubyforge (http://rubyforge.org/projects/apetag/).
37
38
  #
38
- # The most current source code can be accessed via anonymous SVN at
39
- # svn://code.jeremyevans.net/ruby-apetag/. Note that the library isn't modified
40
- # on a regular basis, so it is unlikely to be different from the latest release.
39
+ # The RDoc for the project is available at http://apetag.rubyforge.org.
40
+ #
41
+ # The most current source code can be accessed via github
42
+ # (http://github.com/jeremyevans/ape_tag_libs). Note that the
43
+ # library isn't modified on a regular basis, so it is unlikely to be different
44
+ # from the latest release.
41
45
  #
42
46
  # (1) http://wiki.hydrogenaudio.org/index.php?title=APEv2_specification
43
47
  #
@@ -101,7 +105,11 @@ class ApeItem < Array
101
105
  key_end = data.index("\0", offset += 8)
102
106
  raise ApeTagError, "Missing key-value separator at offset #{offset}" unless key_end
103
107
  raise ApeTagError, "Invalid item length at offset #{offset}" if (next_item_start=length + key_end + 1) > data.length
104
- item = ApeItem.new(data[offset...key_end], data[(key_end+1)...next_item_start].split("\0"))
108
+ begin
109
+ item = ApeItem.new(data[offset...key_end], data[(key_end+1)...next_item_start].split("\0"))
110
+ rescue ArgumentError =>e
111
+ raise ApeTagError, "ArgumentError: #{e.message}"
112
+ end
105
113
  item.read_only = flags & 1 > 0
106
114
  item.ape_type = ITEM_TYPES[flags/2]
107
115
  return [item, next_item_start]
@@ -162,7 +170,7 @@ class ApeItem < Array
162
170
 
163
171
  # Check if the given key is a valid APE key (string, 2 <= length <= 255, not containing invalid characters or keys).
164
172
  def valid_key?(key)
165
- key.is_a?(String) && key.length >= 2 && key.length <= 255 && key !~ BAD_KEY_RE
173
+ key.is_a?(String) && key.length >= 2 && key.length <= 255 && (key !~ BAD_KEY_RE rescue false)
166
174
  end
167
175
 
168
176
  # Check if the given read only flag is valid (boolean).
@@ -7,11 +7,24 @@ require 'test/unit'
7
7
  EMPTY_APE_TAG = "APETAGEX\320\a\0\0 \0\0\0\0\0\0\0\0\0\0\240\0\0\0\0\0\0\0\0APETAGEX\320\a\0\0 \0\0\0\0\0\0\0\0\0\0\200\0\0\0\0\0\0\0\0TAG\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377"
8
8
  EXAMPLE_APE_TAG = "APETAGEX\xd0\x07\x00\x00\xb0\x00\x00\x00\x06\x00\x00\x00\x00\x00\x00\xa0\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00Track\x001\x04\x00\x00\x00\x00\x00\x00\x00Date\x002007\t\x00\x00\x00\x00\x00\x00\x00Comment\x00XXXX-0000\x0b\x00\x00\x00\x00\x00\x00\x00Title\x00Love Cheese\x0b\x00\x00\x00\x00\x00\x00\x00Artist\x00Test Artist\x16\x00\x00\x00\x00\x00\x00\x00Album\x00Test Album\x00Other AlbumAPETAGEX\xd0\x07\x00\x00\xb0\x00\x00\x00\x06\x00\x00\x00\x00\x00\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00TAGLove Cheese\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00Test Artist\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00Test Album, Other Album\x00\x00\x00\x00\x00\x00\x002007XXXX-0000\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\xff"
9
9
  EXAMPLE_APE_TAG2 = "APETAGEX\xd0\x07\x00\x00\x99\x00\x00\x00\x05\x00\x00\x00\x00\x00\x00\xa0\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00Blah\x00Blah\x04\x00\x00\x00\x00\x00\x00\x00Date\x002007\t\x00\x00\x00\x00\x00\x00\x00Comment\x00XXXX-0000\x0b\x00\x00\x00\x00\x00\x00\x00Artist\x00Test Artist\x16\x00\x00\x00\x00\x00\x00\x00Album\x00Test Album\x00Other AlbumAPETAGEX\xd0\x07\x00\x00\x99\x00\x00\x00\x05\x00\x00\x00\x00\x00\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00TAG\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00Test Artist\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00Test Album, Other Album\x00\x00\x00\x00\x00\x00\x002007XXXX-0000\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff"
10
+ [EMPTY_APE_TAG, EXAMPLE_APE_TAG, EXAMPLE_APE_TAG2].each{|x| x.force_encoding('binary')} if RUBY_VERSION >= '1.9.0'
10
11
  EMPTY_APE_ONLY_TAG, EXAMPLE_APE_ONLY_TAG, EXAMPLE_APE_ONLY_TAG2 = [EMPTY_APE_TAG, EXAMPLE_APE_TAG, EXAMPLE_APE_TAG2].collect{|x|x[0...-128]}
11
12
  EXAMPLE_APE_FIELDS = {"Track"=>["1"], "Comment"=>["XXXX-0000"], "Album"=>["Test Album", "Other Album"], "Title"=>["Love Cheese"], "Artist"=>["Test Artist"], "Date"=>["2007"]}
12
13
  EXAMPLE_APE_FIELDS2 = {"Blah"=>["Blah"], "Comment"=>["XXXX-0000"], "Album"=>["Test Album", "Other Album"], "Artist"=>["Test Artist"], "Date"=>["2007"]}
13
14
  EXAMPLE_APE_TAG_PRETTY_PRINT = "Album: Test Album, Other Album\nArtist: Test Artist\nComment: XXXX-0000\nDate: 2007\nTitle: Love Cheese\nTrack: 1"
14
15
 
16
+ class String
17
+ if RUBY_VERSION > '1.9.0'
18
+ def binary
19
+ force_encoding('binary')
20
+ end
21
+ else
22
+ def binary
23
+ self
24
+ end
25
+ end
26
+ end
27
+
15
28
  class ApeTagTest < Test::Unit::TestCase
16
29
  def get_ape_tag(f, check_id3)
17
30
  f.is_a?(ApeTag) ? f : ApeTag.new(f, check_id3)
@@ -169,17 +182,11 @@ class ApeTagTest < Test::Unit::TestCase
169
182
  assert_equal 1, ac.length
170
183
  assert_equal 'Blah', ac.string_value
171
184
 
172
- # Test create works with random object (Hash in this case)
173
- ac = ApeItem.create('Blah', 'xfe'=>132)
174
- assert_equal ApeItem, ac.class
175
- assert_equal 1, ac.length
176
- assert_equal 'xfe132', ac.string_value
177
-
178
185
  # Test create works with array of mixed objects
179
- ac = ApeItem.create('Blah', ['sadf', 'adsfas', 11, {'xfe'=>132}])
186
+ ac = ApeItem.create('Blah', ['sadf', 'adsfas', 11])
180
187
  assert_equal ApeItem, ac.class
181
- assert_equal 4, ac.length
182
- assert_equal "sadf\0adsfas\00011\0xfe132", ac.string_value
188
+ assert_equal 3, ac.length
189
+ assert_equal "sadf\0adsfas\00011", ac.string_value
183
190
  end
184
191
 
185
192
  # Test ApeItem.parse
@@ -204,25 +211,25 @@ class ApeTagTest < Test::Unit::TestCase
204
211
  assert_raises(ApeTagError){ApeItem.parse(data, 1)}
205
212
 
206
213
  # Test parsing with bad/good flags
207
- data[4] = 8
214
+ data[4,1] = 8.chr
208
215
  assert_raises(ApeTagError){ApeItem.parse(data, 0)}
209
- data[4] = 0
216
+ data[4,1] = 0.chr
210
217
  assert_nothing_raised{ApeItem.parse(data, 0)}
211
218
 
212
219
  # Test parsing with length longer than string
213
- data[0] = 9
220
+ data[0,1] = 9.chr
214
221
  assert_raises(ApeTagError){ApeItem.parse(data, 0)}
215
222
 
216
223
  # Test parsing with length shorter than string gives valid ApeItem
217
224
  # Of course, the next item will probably be parsed incorrectly
218
- data[0] = 3
225
+ data[0,1] = 3.chr
219
226
  assert_nothing_raised{ai, offset = ApeItem.parse(data, 0)}
220
227
  assert_equal 16, offset
221
228
  assert_equal "BlaH", ai.key
222
229
  assert_equal "BlA", ai.string_value
223
230
 
224
231
  # Test parsing gets correct key end
225
- data[12] = '3'
232
+ data[12,1] = "3"
226
233
  assert_nothing_raised{ai, offset = ApeItem.parse(data, 0)}
227
234
  assert_equal "BlaH3BlAh", ai.key
228
235
  assert_equal "XYZ", ai.string_value
@@ -239,41 +246,41 @@ class ApeTagTest < Test::Unit::TestCase
239
246
  assert_nothing_raised{ApeTag.new(StringIO.new(data)).raw}
240
247
 
241
248
  # Test read only tags work
242
- data[20] = 1
249
+ data[20,1] = 1.chr
243
250
  assert_nothing_raised{ApeTag.new(StringIO.new(data)).raw}
244
251
 
245
252
  # Test other flags values don't work
246
253
  2.upto(255) do |i|
247
- data[20] = i
254
+ data[20,1] = i.chr
248
255
  assert_raises(ApeTagError){ApeTag.new(StringIO.new(data)).raw}
249
256
  end
250
- data[20] = 1
257
+ data[20,1] = 1.chr
251
258
  2.upto(255) do |i|
252
- data[52] = i
259
+ data[52,1] = i.chr
253
260
  assert_raises(ApeTagError){ApeTag.new(StringIO.new(data)).raw}
254
- data[20] = i
261
+ data[20,1] = i.chr
255
262
  assert_raises(ApeTagError){ApeTag.new(StringIO.new(data)).raw}
256
263
  end
257
264
 
258
265
  # Test footer size less than minimum size (32)
259
- data[44] = 31
266
+ data[44,1] = 31.chr
260
267
  assert_raises(ApeTagError){ApeTag.new(StringIO.new(data)).raw}
261
- data[44] = 0
268
+ data[44,1] = 0.chr
262
269
  assert_raises(ApeTagError){ApeTag.new(StringIO.new(data)).raw}
263
270
 
264
271
  # Test tag size > 8192, when both larger than file and smaller than file
265
- data[44] = 225
266
- data[45] = 31
272
+ data[44,1] = 225.chr
273
+ data[45,1] = 31.chr
267
274
  assert_raises(ApeTagError){ApeTag.new(StringIO.new(data)).raw}
268
275
  assert_raises(ApeTagError){ApeTag.new(StringIO.new(' '*8192+data)).raw}
269
276
 
270
277
  data = EMPTY_APE_TAG.dup
271
278
  # Test unmatching header and footer tag size, with footer size wrong
272
- data[44] = 33
279
+ data[44,1] = 33.chr
273
280
  assert_raises(ApeTagError){ApeTag.new(StringIO.new(data)).raw}
274
281
 
275
282
  # Test matching header and footer but size to large for file
276
- data[12] = 33
283
+ data[12,1] = 33.chr
277
284
  assert_raises(ApeTagError){ApeTag.new(StringIO.new(data)).raw}
278
285
 
279
286
  # Test that header and footer size isn't too large for file, but doesn't
@@ -282,51 +289,51 @@ class ApeTagTest < Test::Unit::TestCase
282
289
  assert_raises(ApeTagError){ApeTag.new(StringIO.new(data)).raw}
283
290
 
284
291
  # Test unmatching header and footer tag size, with header size wrong
285
- data[45] = 32
292
+ data[45,1] = 32.chr
286
293
  assert_raises(ApeTagError){ApeTag.new(StringIO.new(data)).raw}
287
294
 
288
295
  data = EMPTY_APE_TAG.dup
289
296
  # Test item count greater than maximum (64)
290
- data[48] = 65
297
+ data[48,1] = 65.chr
291
298
  assert_raises(ApeTagError){ApeTag.new(StringIO.new(data)).raw}
292
299
 
293
300
  # Test item count greater than possible given tag size
294
- data[48] = 1
301
+ data[48,1] = 1.chr
295
302
  assert_raises(ApeTagError){ApeTag.new(StringIO.new(data)).raw}
296
303
 
297
304
  # Test unmatched header and footer item count, header size wrong
298
- data[48] = 0
299
- data[16] = 1
305
+ data[48,1] = 0.chr
306
+ data[16,1] = 1.chr
300
307
  assert_raises(ApeTagError){ApeTag.new(StringIO.new(data)).raw}
301
308
 
302
309
  # Test unmatched header and footer item count, footer size wrong
303
310
  data = EXAMPLE_APE_TAG.dup
304
- data[208-16] -=1
311
+ data[208-16] = 5.chr
305
312
  assert_raises(ApeTagError){ApeTag.new(StringIO.new(data)).fields}
306
313
 
307
314
  # Test missing/corrupt header
308
315
  data = EMPTY_APE_TAG.dup
309
- data[0] = 0
316
+ data[0,1] = 0.chr
310
317
  assert_raises(ApeTagError){ApeTag.new(StringIO.new(data)).fields}
311
318
 
312
319
  # Test parsing bad first item size
313
320
  data = EXAMPLE_APE_TAG.dup
314
- data[32] +=1
321
+ data[32,1] = 2.chr
315
322
  assert_raises(ApeTagError){ApeTag.new(StringIO.new(data)).fields}
316
323
 
317
324
  # Test parsing bad first item invalid key
318
325
  data = EXAMPLE_APE_TAG.dup
319
- data[40] = 0
326
+ data[40,1] = 0.chr
320
327
  assert_raises(ApeTagError){ApeTag.new(StringIO.new(data)).fields}
321
328
 
322
329
  # Test parsing bad first item key end
323
330
  data = EXAMPLE_APE_TAG.dup
324
- data[45] = 1
331
+ data[45,1] = 1.chr
325
332
  assert_raises(ApeTagError){ApeTag.new(StringIO.new(data)).fields}
326
333
 
327
334
  # Test parsing bad second item length too long
328
335
  data = EXAMPLE_APE_TAG.dup
329
- data[47] = 255
336
+ data[47,1] = 255.chr
330
337
  assert_raises(ApeTagError){ApeTag.new(StringIO.new(data)).fields}
331
338
 
332
339
  # Test parsing case insensitive duplicate keys
@@ -340,11 +347,11 @@ class ApeTagTest < Test::Unit::TestCase
340
347
 
341
348
  # Test parsing incorrect item counts
342
349
  data = EXAMPLE_APE_TAG.dup
343
- data[16] -= 1
344
- data[192] -= 1
350
+ data[16,1] = 5.chr
351
+ data[192,1] = 5.chr
345
352
  assert_raises(ApeTagError){ApeTag.new(StringIO.new(data)).fields}
346
- data[16] += 2
347
- data[192] += 2
353
+ data[16,1] = 7.chr
354
+ data[192,1] = 7.chr
348
355
  assert_raises(ApeTagError){ApeTag.new(StringIO.new(data)).fields}
349
356
 
350
357
  # Test updating works in a case insensitive manner
metadata CHANGED
@@ -1,54 +1,83 @@
1
1
  --- !ruby/object:Gem::Specification
2
- rubygems_version: 0.9.4
3
- specification_version: 1
4
2
  name: apetag
5
3
  version: !ruby/object:Gem::Version
6
- version: 1.1.2
7
- date: 2007-11-07 00:00:00 -08:00
8
- summary: APEv2 Tag Reader/Writer
9
- require_paths:
10
- - .
11
- email: code@jeremyevans.net
12
- homepage:
13
- rubyforge_project: apetag
14
- description:
15
- autorequire: apetag
16
- default_executable:
17
- bindir: bin
18
- has_rdoc: true
19
- required_ruby_version: !ruby/object:Gem::Version::Requirement
20
- requirements:
21
- - - ">"
22
- - !ruby/object:Gem::Version
23
- version: 0.0.0
24
- version:
4
+ hash: 21
5
+ prerelease: false
6
+ segments:
7
+ - 1
8
+ - 1
9
+ - 3
10
+ version: 1.1.3
25
11
  platform: ruby
26
- signing_key:
27
- cert_chain:
28
- post_install_message:
29
12
  authors:
30
13
  - Jeremy Evans
31
- files:
32
- - apetag.rb
33
- test_files:
34
- - test/test_apetag.rb
35
- rdoc_options: []
36
-
37
- extra_rdoc_files: []
38
-
39
- executables: []
40
-
41
- extensions: []
42
-
43
- requirements: []
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
44
17
 
18
+ date: 2011-01-16 00:00:00 -08:00
19
+ default_executable:
45
20
  dependencies:
46
21
  - !ruby/object:Gem::Dependency
47
22
  name: cicphash
48
- version_requirement:
49
- version_requirements: !ruby/object:Gem::Version::Requirement
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
50
26
  requirements:
51
27
  - - ">="
52
28
  - !ruby/object:Gem::Version
29
+ hash: 23
30
+ segments:
31
+ - 1
32
+ - 0
33
+ - 0
53
34
  version: 1.0.0
54
- version:
35
+ type: :runtime
36
+ version_requirements: *id001
37
+ description:
38
+ email: code@jeremyevans.net
39
+ executables: []
40
+
41
+ extensions: []
42
+
43
+ extra_rdoc_files: []
44
+
45
+ files:
46
+ - apetag.rb
47
+ - test/test_apetag.rb
48
+ has_rdoc: true
49
+ homepage: http://apetag.rubyforge.org
50
+ licenses: []
51
+
52
+ post_install_message:
53
+ rdoc_options: []
54
+
55
+ require_paths:
56
+ - .
57
+ required_ruby_version: !ruby/object:Gem::Requirement
58
+ none: false
59
+ requirements:
60
+ - - ">="
61
+ - !ruby/object:Gem::Version
62
+ hash: 3
63
+ segments:
64
+ - 0
65
+ version: "0"
66
+ required_rubygems_version: !ruby/object:Gem::Requirement
67
+ none: false
68
+ requirements:
69
+ - - ">="
70
+ - !ruby/object:Gem::Version
71
+ hash: 3
72
+ segments:
73
+ - 0
74
+ version: "0"
75
+ requirements: []
76
+
77
+ rubyforge_project: apetag
78
+ rubygems_version: 1.3.7
79
+ signing_key:
80
+ specification_version: 3
81
+ summary: APEv2 Tag Reader/Writer
82
+ test_files:
83
+ - test/test_apetag.rb