apetag 1.1.3 → 1.1.4

Sign up to get free protection for your applications and to get access to all the features.
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