apetag 1.1.3 → 1.1.4

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 +50 -31
  2. data/test/test_apetag.rb +28 -0
  3. metadata +4 -4
data/apetag.rb CHANGED
@@ -11,10 +11,8 @@
11
11
  # used on any file type and is not limited to storing just audio file metadata).
12
12
  #
13
13
  # The module is in written in pure Ruby, so it should be useable on all
14
- # platforms that Ruby supports. It is developed and tested on OpenBSD.
15
- # The minimum Ruby version required should be 1.8, but it has only been tested
16
- # on 1.8.4+. Modifying the code to work with previous version shouldn't be
17
- # difficult, though there aren't any plans to do so.
14
+ # platforms that Ruby supports. It is developed and tested on OpenBSD
15
+ # with ruby 1.8 and ruby 1.9.
18
16
  #
19
17
  # General Use:
20
18
  #
@@ -44,26 +42,6 @@
44
42
  # from the latest release.
45
43
  #
46
44
  # (1) http://wiki.hydrogenaudio.org/index.php?title=APEv2_specification
47
- #
48
- # Copyright (c) 2007 Jeremy Evans
49
- #
50
- # Permission is hereby granted, free of charge, to any person obtaining a copy
51
- # of this software and associated documentation files (the "Software"), to deal
52
- # in the Software without restriction, including without limitation the rights
53
- # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
54
- # copies of the Software, and to permit persons to whom the Software is
55
- # furnished to do so, subject to the following conditions:
56
- #
57
- # The above copyright notice and this permission notice shall be included in
58
- # all copies or substantial portions of the Software.
59
- #
60
- # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
61
- # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
62
- # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
63
- # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
64
- # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
65
- # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
66
- # SOFTWARE.
67
45
 
68
46
  require 'cicphash'
69
47
 
@@ -106,7 +84,7 @@ class ApeItem < Array
106
84
  raise ApeTagError, "Missing key-value separator at offset #{offset}" unless key_end
107
85
  raise ApeTagError, "Invalid item length at offset #{offset}" if (next_item_start=length + key_end + 1) > data.length
108
86
  begin
109
- item = ApeItem.new(data[offset...key_end], data[(key_end+1)...next_item_start].split("\0"))
87
+ item = ApeItem.new_from_parse(data[offset...key_end], data[(key_end+1)...next_item_start].split("\0"))
110
88
  rescue ArgumentError =>e
111
89
  raise ApeTagError, "ArgumentError: #{e.message}"
112
90
  end
@@ -135,16 +113,17 @@ class ApeItem < Array
135
113
  # Set key if valid, otherwise raise ApeTagError.
136
114
  def key=(key)
137
115
  raise ApeTagError, "Invalid APE key" unless valid_key?(key)
138
- @key = key
116
+ @key = encoded_key(key)
139
117
  end
140
-
118
+
141
119
  # The on disk representation of the entire ApeItem.
142
120
  # Raise ApeTagError if ApeItem is invalid.
143
121
  def raw
144
122
  raise ApeTagError, "Invalid key, value, APE type, or Read-Only Flag" unless valid?
145
123
  flags = ITEM_TYPES.index(ape_type) * 2 + (read_only ? 1 : 0)
146
- sv = string_value
147
- "#{[sv.length, flags].pack('VN')}#{key}\0#{sv}"
124
+ k = RUBY_VERSION >= '1.9' ? key.dup.force_encoding('BINARY') : key
125
+ sv = RUBY_VERSION >= '1.9' ? string_value.dup.force_encoding('BINARY') : string_value
126
+ "#{[sv.length, flags].pack('VN')}#{k}\0#{sv}"
148
127
  end
149
128
 
150
129
  # Set read only flag if valid, otherwise raise ApeTagError.
@@ -170,7 +149,9 @@ class ApeItem < Array
170
149
 
171
150
  # Check if the given key is a valid APE key (string, 2 <= length <= 255, not containing invalid characters or keys).
172
151
  def valid_key?(key)
173
- key.is_a?(String) && key.length >= 2 && key.length <= 255 && (key !~ BAD_KEY_RE rescue false)
152
+ return false unless key.is_a?(String)
153
+ return false unless key = encoded_key(key)
154
+ key.length >= 2 && key.length <= 255 && (key !~ BAD_KEY_RE rescue false)
174
155
  end
175
156
 
176
157
  # Check if the given read only flag is valid (boolean).
@@ -181,6 +162,13 @@ class ApeItem < Array
181
162
  # Check if the string value is valid UTF-8.
182
163
  def valid_value?
183
164
  begin
165
+ if RUBY_VERSION >= '1.9'
166
+ begin
167
+ map!{|v| v.to_s.encode('UTF-8')}
168
+ rescue EncodingError
169
+ return false
170
+ end
171
+ end
184
172
  string_value.unpack('U*') if ape_type == 'utf8' || ape_type == 'external'
185
173
  rescue ArgumentError
186
174
  false
@@ -188,6 +176,37 @@ class ApeItem < Array
188
176
  true
189
177
  end
190
178
  end
179
+
180
+ if RUBY_VERSION >= '1.9.0'
181
+ def self.new_from_parse(key, value)
182
+ new(key.force_encoding('US-ASCII'), value.map{|v| v.to_s.force_encoding('UTF-8')})
183
+ end
184
+
185
+ def encoded_key(key)
186
+ begin
187
+ key.encode('US-ASCII')
188
+ rescue EncodingError
189
+ return false
190
+ end
191
+ end
192
+
193
+ def normalize_encodings
194
+ map!{|v| v.to_s.encode('UTF-8')}
195
+ self
196
+ end
197
+ else
198
+ def self.new_from_parse(key, value)
199
+ new(key, value)
200
+ end
201
+
202
+ def encoded_key(key)
203
+ key
204
+ end
205
+
206
+ def normalize_encodings
207
+ self
208
+ end
209
+ end
191
210
  end
192
211
 
193
212
  # Contains all of the ApeItems found in the filename/file given.
@@ -421,7 +440,7 @@ class ApeTag
421
440
  def normalize_fields
422
441
  new_fields = CICPHash.new
423
442
  fields.each do |key, value|
424
- new_fields[key] = ApeItem.create(key, value)
443
+ new_fields[key] = ApeItem.create(key, value).normalize_encodings
425
444
  end
426
445
  @fields = new_fields
427
446
  end
data/test/test_apetag.rb CHANGED
@@ -445,4 +445,32 @@ class ApeTagTest < Test::Unit::TestCase
445
445
  assert_equal 0, get_size(filename)
446
446
  File.delete(filename)
447
447
  end
448
+
449
+ if RUBY_VERSION > '1.9.0'
450
+ def test_apeitem_encoding
451
+ ApeTag.new(StringIO.new(EXAMPLE_APE_TAG)).fields.each do |k, vs|
452
+ assert_equal 'US-ASCII', k.encoding.name
453
+ assert_equal 'US-ASCII', vs.key.encoding.name
454
+ vs.each{|v| assert_equal 'UTF-8', v.encoding.name}
455
+ end
456
+ end
457
+
458
+ def test_item_and_key_encoding
459
+ filename = 'test.apetag'
460
+ File.new(filename,'wb').close
461
+ utf8_key = File.read('test/utf-8.key', :mode=>'rb:UTF-8')
462
+ utf8_values = File.read('test/utf-8.values', :mode=>'rb:UTF-8')
463
+ utf16_key = File.read('test/utf-16be.key', :mode=>'rb:UTF-16BE')
464
+ utf16_values = File.read('test/utf-16be.values', :mode=>'rb:UTF-16BE')
465
+ latin1_values = File.read('test/latin1.values', :mode=>'rb:ISO-8859-1')
466
+ ApeTag.new(filename).update do |f|
467
+ f[utf16_key] = utf16_values.split('\n'.force_encoding('UTF-16BE'))
468
+ f['foo'] = latin1_values.split('\n'.force_encoding('ISO-8859-1'))
469
+ end
470
+ f = ApeTag.new(filename).fields
471
+ assert_equal utf8_values.split('\n'.force_encoding('UTF-8')), f[utf8_key]
472
+ assert_equal utf8_values.split('\n'.force_encoding('UTF-8')), f['foo']
473
+ File.delete(filename)
474
+ end
475
+ end
448
476
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: apetag
3
3
  version: !ruby/object:Gem::Version
4
- hash: 21
4
+ hash: 27
5
5
  prerelease: false
6
6
  segments:
7
7
  - 1
8
8
  - 1
9
- - 3
10
- version: 1.1.3
9
+ - 4
10
+ version: 1.1.4
11
11
  platform: ruby
12
12
  authors:
13
13
  - Jeremy Evans
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2011-01-16 00:00:00 -08:00
18
+ date: 2011-01-21 00:00:00 -08:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency