id3 0.5.0 → 1.0.0.pre4

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.
@@ -0,0 +1,20 @@
1
+ #
2
+ # EXTENSIONS to Class Hash
3
+ #
4
+
5
+ # include Hash#inverse from Facets of Ruby or from our helper
6
+ # then Monkey-Patch the Hash#invert method:
7
+
8
+ require 'helpers/invert_hash'
9
+
10
+ class Hash
11
+ # original Hash#invert is still available as Hash#old_invert
12
+ alias old_invert invert
13
+
14
+ # monkey-patching Hash#invert method - it's backwards compatible, but preserves duplicate values in the hash
15
+ def invert
16
+ self.inverse
17
+ end
18
+ end
19
+
20
+
@@ -0,0 +1,136 @@
1
+ # ==============================================================================
2
+ # EXTENDING CLASS STRING
3
+ # ==============================================================================
4
+ # --
5
+ # (C) Copyright 2004 by Tilo Sloboda <tools@unixgods.org>
6
+ #
7
+ # License:
8
+ # Freely available under the terms of the OpenSource "Artistic License"
9
+ # in combination with the Addendum A (below)
10
+ #
11
+ # In case you did not get a copy of the license along with the software,
12
+ # it is also available at: http://www.unixgods.org/~tilo/artistic-license.html
13
+ #
14
+ # Addendum A:
15
+ # THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU!
16
+ # SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
17
+ # REPAIR OR CORRECTION.
18
+ #
19
+ # IN NO EVENT WILL THE COPYRIGHT HOLDERS BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL,
20
+ # SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY
21
+ # TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED
22
+ # INACCURATE OR USELESS OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM
23
+ # TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF THE COPYRIGHT HOLDERS OR OTHER PARTY HAS BEEN
24
+ # ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
25
+ #++
26
+
27
+ # this is written for Ruby version < 1.9 - unfortunately they changed the I/O and String classes significantly.
28
+ # have to fix this up for newer Ruby versions.
29
+
30
+ if RUBY_VERSION >= "1.9.0"
31
+ ZEROBYTE = "\x00".force_encoding(Encoding::BINARY) unless defined? ZEROBYTE
32
+
33
+ else # older Ruby versions:
34
+
35
+ class String
36
+ alias bytesize size
37
+
38
+ def getbyte(x) # when accessing a string and selecting x-th byte to do calculations , as defined in Ruby 1.9
39
+ self[x] # returns an integer
40
+ end
41
+ end
42
+
43
+ ZEROBYTE = "\0" unless defined? ZEROBYTE
44
+ end
45
+
46
+
47
+ class String
48
+ #
49
+ # prints out a good'ol hexdump of the data contained in the string
50
+ #
51
+ # parameters: sparse: true / false do we want to print multiple lines with zero values?
52
+
53
+ def hexdump(sparse = false)
54
+
55
+ selfsize = self.bytesize
56
+
57
+ first = true
58
+
59
+ print "\n index 0 1 2 3 4 5 6 7 8 9 A B C D E F\n\n"
60
+
61
+ lines,rest = selfsize.divmod(16)
62
+ address = 0; i = 0 # we count them independently for future extension.
63
+
64
+ while lines > 0
65
+ str = self[i..i+15]
66
+
67
+ # we don't print lines with all zeroes, unless it's the last line
68
+
69
+ if str == ZEROBYTE * 16 # if the 16 bytes are all zero
70
+
71
+ if (!sparse) || (sparse && lines == 1 && rest == 0)
72
+ str.tr!("\000-\037\177-\377",'.')
73
+
74
+ printf( "%08x %8s %8s %8s %8s %s\n",
75
+ address, self[i..i+3].unpack('H8').first, self[i+4..i+7].unpack('H8').first,
76
+ self[i+8..i+11].unpack('H8').first, self[i+12..i+15].unpack('H8').first, str)
77
+ else
78
+ print " .... 00 .. 00 00 .. 00 00 .. 00 00 .. 00 ................\n" if first
79
+ first = false
80
+ end
81
+
82
+ else # print string which is not all zeros
83
+
84
+ str.tr!("\000-\037\177-\377",'.')
85
+
86
+ printf( "%08x %8s %8s %8s %8s %s\n",
87
+ address, self[i..i+3].unpack('H8').first, self[i+4..i+7].unpack('H8').first,
88
+ self[i+8..i+11].unpack('H8').first, self[i+12..i+15].unpack('H8').first, str)
89
+ first = true
90
+ end
91
+ i += 16; address += 16; lines -= 1
92
+ end
93
+
94
+ # now do the remaining bytes, which don't fit a full line..
95
+ # yikes - this is truly ugly! REWRITE THIS!!
96
+
97
+ if rest > 0
98
+ chunks2,rest2 = rest.divmod(4)
99
+ j = i; k = 0
100
+ if (i < selfsize)
101
+ printf( "%08x ", address)
102
+ while (i < selfsize)
103
+ printf "%02x", self.getbyte(i)
104
+ i += 1; k += 1
105
+ print " " if ((i % 4) == 0)
106
+ end
107
+ for i in (k..15)
108
+ print " "
109
+ end
110
+ str = self[j..selfsize]
111
+ str.tr!("\000-\037\177-\377",'.')
112
+ print " " * (4 - chunks2+1)
113
+ printf(" %s\n", str)
114
+ end
115
+ end
116
+ end
117
+
118
+ end
119
+
120
+
121
+
122
+ __END__
123
+
124
+
125
+ # you would use it like this:
126
+
127
+ require './hexdump'
128
+
129
+ s = "some random long string"
130
+
131
+ t = s + ZEROBYTE*80 + s + ZEROBYTE*64 + s + "bla bla bla!"
132
+ t.hexdump(true) # surpress consecutive lines with zero values
133
+ t.hexdump # same as t.hexdump(false)
134
+
135
+
136
+
@@ -0,0 +1,128 @@
1
+ # ==============================================================================
2
+ # EXTENDING CLASS HASH
3
+ # ==============================================================================
4
+ #--
5
+ # (C) Copyright 2004 by Tilo Sloboda <tools@unixgods.org>
6
+ #
7
+ # updated: Time-stamp: <Mon, 24 Oct 2011, 23:03:29 PDT tilo>
8
+ #
9
+ # License:
10
+ # Freely available under the terms of the OpenSource "Artistic License"
11
+ # in combination with the Addendum A (below)
12
+ #
13
+ # In case you did not get a copy of the license along with the software,
14
+ # it is also available at: http://www.unixgods.org/~tilo/artistic-license.html
15
+ #
16
+ # Addendum A:
17
+ # THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU!
18
+ # SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
19
+ # REPAIR OR CORRECTION.
20
+ #
21
+ # IN NO EVENT WILL THE COPYRIGHT HOLDERS BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL,
22
+ # SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY
23
+ # TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED
24
+ # INACCURATE OR USELESS OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM
25
+ # TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF THE COPYRIGHT HOLDERS OR OTHER PARTY HAS BEEN
26
+ # ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
27
+ #++
28
+ # ==============================================================================
29
+
30
+ # Project Homepage: http://www.unixgods.org/~tilo/Ruby/invert_hash.html
31
+ #
32
+ # This also appears in the "Facets of Ruby" library, and is mentioned in the O'Reilly Ruby Cookbook
33
+ #
34
+ # Ruby's Hash.invert method can't handle the common case that two or more hash entries have the same value.
35
+ #
36
+ # hash.invert.invert == h # => ? # is not generally true for Ruby's standard Hash#invert method
37
+ #
38
+ # hash.inverse.inverse == h # => true # is true, even if the hash has duplicate values
39
+ #
40
+ # If you have a Math background, you would expect that performing an "invert" operation twice would result in the original hash.
41
+ #
42
+ # The Hash#inverse method provides this.
43
+ #
44
+ #
45
+ # If you want to permanently overload Ruby's original invert method, you may want to do this:
46
+ #
47
+ # class Hash
48
+ # alias old_invert invert # old Hash#invert is still accessible as Hash#old_invert
49
+ #
50
+ # def invert
51
+ # self.inverse # Hash#invert is not using inverse method
52
+ # end
53
+ # end
54
+
55
+ class Hash
56
+
57
+ # Returns a new hash, using given hash's values as keys and using keys as values.
58
+ # If the input hash has duplicate values, the resulting hash will contain arrays as values.
59
+ # If you perform inverse twice, the output is identical to the original hash.
60
+ # e.g. no data is lost.
61
+ #
62
+ # hash = { 'zero' => 0 , 'one' => 1, 'two' => 2, 'three' => 3 , # English numbers
63
+ # 'null' => 0, 'eins' => 1, 'zwei' => 2 , 'drei' => 3 } # German numbers
64
+ #
65
+ # # Hash#inverse keeps track of duplicates, and preserves the input data
66
+ #
67
+ # hash.inverse # => { 0=>["null", "zero"], 1=>["eins", "one"], 2=>["zwei", "two"], 3=>["drei", "three"] }
68
+ #
69
+ # hash.inverse.inverse # => { "null"=>0, "zero"=>0, "eins"=>1, "one"=>1, "zwei"=>2, "two"=>2, "drei"=>3, "three"=>3 }
70
+ #
71
+ # hash.inverse.inverse == hash # => true # works as you'd expect
72
+ #
73
+ # # In Comparison:
74
+ # #
75
+ # # the standard Hash#invert loses data when dupclicate values are present
76
+ #
77
+ # hash.invert # => { 0=>"null", 1=>"eins", 2=>"zwei", 3=>"drei" }
78
+ # hash.invert.invert # => { "null"=>0, "eins"=>1, "zwei"=>2, "drei"=>3 } # data is lost
79
+ #
80
+ # hash.invert.invert == hash # => false # oops, data was lost!
81
+ #
82
+
83
+ def inverse
84
+ i = Hash.new
85
+ self.each_pair{ |k,v|
86
+ if (v.class == Array)
87
+ v.each{ |x|
88
+ if i.has_key?(x)
89
+ i[x] = [k,i[x]].flatten
90
+ else
91
+ i[x] = k
92
+ end
93
+ }
94
+ else
95
+ if i.has_key?(v)
96
+ i[v] = [k,i[v]].flatten
97
+ else
98
+ i[v] = k
99
+ end
100
+ end
101
+ }
102
+ return i
103
+ end
104
+
105
+ end
106
+
107
+
108
+ #--
109
+ #
110
+ # require 'active_support'
111
+ #
112
+ # class Hash
113
+ #
114
+ # def inverse
115
+ # i = ActiveSupport::OrderedHash.new
116
+ # self.each_pair{ |k,v|
117
+ # if (v.class == Array)
118
+ # v.each{ |x|
119
+ # i[x] = i.has_key?(x) ? [i[x],k].flatten : k
120
+ # }
121
+ # else
122
+ # i[v] = i.has_key?(v) ? [i[v],k].flatten : k
123
+ # end
124
+ # }
125
+ # return i
126
+ # end
127
+ #
128
+ # end
@@ -0,0 +1,39 @@
1
+ # module ID3
2
+ # module Helpers
3
+
4
+ # ------------------------------------------------------------------------------
5
+ # recursiveDirectoryDescend
6
+ # do action for files matching regexp
7
+ #
8
+ # could be extended to array of (regexp,action) pairs
9
+ #
10
+ def recursive_dir_descend(dir,regexp,action)
11
+ # print "dir : #{dir}\n"
12
+
13
+ olddir = Dir.pwd
14
+ dirp = Dir.open(dir)
15
+ Dir.chdir(dir)
16
+ pwd = Dir.pwd
17
+ @dirN += 1
18
+
19
+ for file in dirp
20
+ file.chomp
21
+ next if file =~ /^\.\.?$/
22
+ filename = "#{pwd}/#{file}"
23
+
24
+ if File::directory?(filename)
25
+ recursive_dir_descend(filename,regexp,action)
26
+ else
27
+ @fileN += 1
28
+ if file =~ regexp
29
+ # evaluate action
30
+ eval action
31
+ end
32
+ end
33
+ end
34
+ Dir.chdir(olddir)
35
+ end
36
+ # ------------------------------------------------------------------------------
37
+
38
+ # end
39
+ # end
@@ -0,0 +1,88 @@
1
+ require 'id3/frame_array'
2
+
3
+ # ==============================================================================
4
+ # Class RestrictedOrderedHash
5
+ # this is a helper Class for ID3::Frame
6
+ #
7
+ # this is a helper Class for GenericTag
8
+ #
9
+ # this is from 2002 .. new Ruby Versions now have "OrderedHash" .. but I'll keep this class for now.
10
+
11
+ class RestrictedOrderedHash < ActiveSupport::OrderedHash
12
+
13
+ attr_accessor :locked
14
+
15
+ def lock
16
+ @locked = true
17
+ end
18
+
19
+ def initialize
20
+ @locked = false
21
+ super
22
+ end
23
+
24
+ alias old_store []=
25
+
26
+ def []= (key,val)
27
+ if self[key]
28
+ # self.old_store(key,val) # this would overwrite the old_value if a key already exists (duplicate ID3-Frames)
29
+
30
+ # strictly speaking, we only need this for the ID3v2 Tag class Tag2:
31
+ if self[key].class != ID3::FrameArray # Make this ID3::FrameArray < Array
32
+ old_value = self[key]
33
+ new_value = ID3::FrameArray.new
34
+ new_value << old_value # make old_value a FrameArray
35
+ self.old_store(key, new_value )
36
+ end
37
+ self[key] << val
38
+
39
+ else
40
+ if @locked
41
+ # we're not allowed to add new keys!
42
+ raise ArgumentError, "You can not add new keys! The ID3-frame #{@name} has fixed entries!\n" +
43
+ " valid key are: " + self.keys.join(",") +"\n"
44
+ else
45
+ self.old_store(key,val)
46
+ end
47
+ end
48
+ end
49
+
50
+ # users can not delete entries from a locked hash..
51
+
52
+ alias old_delete delete
53
+
54
+ def delete(key)
55
+ if !@locked
56
+ old_delete(key)
57
+ end
58
+ end
59
+ end
60
+
61
+
62
+ # ==============================================================================
63
+ # Class RestrictedOrderedHashWithMultipleValues
64
+ # this is a helper Class for ID3::Frame
65
+ #
66
+ # same as the parent class, but if a key is already present, it stores multiple values as an Array of values
67
+
68
+ # class RestrictedOrderedHashWithMultipleValues < RestrictedOrderedHash
69
+ # alias old_store2 []=
70
+
71
+ # # if key already in Hash, then replace value with [ old_value ] and append new value to it.
72
+ # def []= (key,val)
73
+
74
+ # puts "Key: #{key} , Val: #{val} , Class: #{self[key].class}"
75
+
76
+ # if self[key]
77
+ # if self[key].class == ID3::Frame
78
+ # old_value = self[key]
79
+ # self[key] = [ old_value ]
80
+ # end
81
+ # self[key] << value
82
+ # else
83
+ # self.old_store2(key,val)
84
+ # end
85
+ # end
86
+
87
+ # end
88
+
@@ -0,0 +1,62 @@
1
+ # ==============================================================================
2
+ # Loading Libraries and Stuff needed for Ruby 1.9 vs 1.8 Compatibility
3
+ # ==============================================================================
4
+ # the idea here is to define a couple of go-between methods for different classes
5
+ # which are differently defined depending on which Ruby version it is -- thereby
6
+ # abstracting from the particular Ruby version's API of those classes
7
+
8
+ if RUBY_VERSION >= "1.9.0"
9
+ require "digest/md5"
10
+ require "digest/sha1"
11
+ include Digest
12
+
13
+ require 'fileutils' # replaces ftools
14
+ include FileUtils::Verbose
15
+
16
+ class File
17
+ def read_bytes(n) # returns a string containing bytes
18
+ # self.read(n)
19
+ # self.sysread(n)
20
+ self.bytes.take(n)
21
+ end
22
+ def write_bytes(bytes)
23
+ self.syswrite(bytes)
24
+ end
25
+ def get_byte
26
+ self.getbyte # returns a number 0..255
27
+ end
28
+ end
29
+
30
+ ZEROBYTE = "\x00".force_encoding(Encoding::BINARY) unless defined? ZEROBYTE
31
+
32
+ else # older Ruby versions:
33
+ require 'rubygems'
34
+
35
+ require "md5"
36
+ require "sha1"
37
+
38
+ require 'ftools'
39
+ def move(a,b)
40
+ File.move(a,b)
41
+ end
42
+
43
+ class String
44
+ def getbyte(x) # when accessing a string and selecting x-th byte to do calculations , as defined in Ruby 1.9
45
+ self[x] # returns an integer
46
+ end
47
+ end
48
+
49
+ class File
50
+ def read_bytes(n)
51
+ self.read(n) # should use sysread here as well?
52
+ end
53
+ def write_bytes(bytes)
54
+ self.write(bytes) # should use syswrite here as well?
55
+ end
56
+ def get_byte # in older Ruby versions <1.9 getc returned a byte, e.g. a number 0..255
57
+ self.getc # returns a number 0..255
58
+ end
59
+ end
60
+
61
+ ZEROBYTE = "\0" unless defined? ZEROBYTE
62
+ end