id3 0.5.0 → 1.0.0.pre4

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