Method: ID3::Frame#initialize

Defined in:
lib/id3/frame.rb

#initialize(name, version = '2.3.0', flags = 0, tag, headerStartX, dataStartX, dataEndX) ⇒ Frame




67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
# File 'lib/id3/frame.rb', line 67

def initialize(name, version = '2.3.0', flags = 0, tag,  headerStartX, dataStartX, dataEndX )
  super

  @name = name
  @headerStartX = headerStartX if headerStartX
  @dataStartX   = dataStartX   if dataStartX
  @dataEndX     = dataEndX     if dataEndX

  if tag
    @rawdata   = tag.raw[dataStartX..dataEndX]
    @rawheader = tag.raw[headerStartX..dataStartX-1]
    # parse the darn flags, if there are any..
    @version = tag.version  # caching..
  else
    @rawdata = ''
    @rawheader= ''
    @version = version
  end

  case @version
  when /2\.2\.[0-9]/
    # no flags, no extra attributes necessary

  when /2\.[34]\.0/
    
    # dynamically create attributes and reader functions for flags in ID3-frames:
    # (not defined in earlier ID3 versions)
    instance_eval <<-EOB
      class << self 
        attr_reader :rawflags, :flags
      end
    EOB
  
    @rawflags = flags.to_i   # preserve the raw flags (for debugging only)
  
    if (flags.to_i & FRAME_HEADER_FLAG_MASK[@version] != 0)
      # in this case we need to skip parsing the frame... and skip to the next one...
      wrong = flags.to_i & FRAME_HEADER_FLAG_MASK[@version]
      error = printf "ID3 version %s frame header flags 0x%X contain invalid flags 0x%X !\n", @version, flags, wrong
      raise ArgumentError, error
    end
  
    @flags = Hash.new
    
    FRAME_HEADER_FLAGS[@version].each do |key,val|
      # only define the flags which are set..
      @flags[key] = true   if  (flags.to_i & val == 1)
    end
    
  else
    raise ArgumentError, "ID3 version #{@version} not recognized when parsing frame header flags\n"
  end # parsing flags
             
  # generate methods for parsing data (low-level read support) and for dumping data out (low-level write-support)
  #
  # based on the particular ID3-version and the ID3-frame name, we basically obtain a string saying how to pack/unpack the data for that frame
  # then we use that packing-string to define a parser and dump method for this particular frame
             
  instance_eval <<-EOB
    class << self

      def parse
        # here we GENERATE the code to parse, dump and verify  methods
      
        vars,packing = ID3::FRAME_PARSER[ ID3::FrameName2FrameType[ ID3::Framename2symbol[self.version][self.name]] ]

        values = self.rawdata.unpack(packing)

        vars.each do |key|
          self[key] = values.shift
        end
        self.lock   # lock the OrderedHash
      end
      

      def dump
        vars,packing = ID3::FRAME_PARSER[ ID3::FrameName2FrameType[ ID3::Framename2symbol[self.version][self.name]] ]
        
        data = self.values.pack(packing)     # we depend on an OrderedHash, so the values are in the correct order!!!
        header  = self.name.dup         # we want the value! not the reference!!
        len     = data.length
        if self.version =~ /^2\.2\./
          byte2,rest = len.divmod(256**2)
          byte1,byte0 = rest.divmod(256)
          
          header << byte2 << byte1 << byte0
        
        elsif self.version =~ /^2\.[34]\./          # 10-byte header
          byte3,rest = len.divmod(256**3)
          byte2,rest = rest.divmod(256**2)
          byte1,byte0 = rest.divmod(256)            
          
          flags1,flags0 = self.rawflags.divmod(256)
          
          header << byte3 << byte2 << byte1 << byte0 << flags1 << flags0
        end
        header << data
      end
      
    end
  EOB

  self.parse           # now we're using the just defined parsing routine
    
  return self
end