Class: ID3::Frame

Inherits:
RestrictedOrderedHash show all
Defined in:
lib/id3.rb

Overview

Class Frame ID3 Version 2.x.y Frame

parses ID3v2 frames from a binary array
dumps  ID3v2 frames into a binary array
allows to modify frame's contents if the frame was decoded..

Instance Attribute Summary collapse

Attributes inherited from RestrictedOrderedHash

#count, #locked, #order

Instance Method Summary collapse

Methods inherited from RestrictedOrderedHash

#[]=, #delete, #inspect, #lock, #old_delete, #old_store, #values

Methods inherited from Hash

#inverse, #invert, #old_invert

Constructor Details

#initialize(tag, name, headerStartX, dataStartX, dataEndX, flags) ⇒ Frame

Returns a new instance of Frame.



1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
# File 'lib/id3.rb', line 1155

def initialize(tag, name, headerStartX, dataStartX, dataEndX, flags)
   @name = name
   @headerStartX = headerStartX
   @dataStartX   = dataStartX
   @dataEndX     = dataEndX

   @rawdata   = tag.raw[dataStartX..dataEndX]
   @rawheader = tag.raw[headerStartX..dataStartX-1]

   # initialize the super class..
   old_init
   
   # parse the darn flags, if there are any..

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

     when /2\.[34]\.0/
        
        # dynamically create attributes and reader functions:
        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{ |key,val|
          # only define the flags which are set..
          @flags[key] = true   if  (flags.to_i & val == 1)
        }
        
     else
        raise ArgumentError, "ID3 version #{@version} not recognized when parsing frame header flags\n"
   end # parsing flags

   # generate method for parsing data
   
   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]] ]

            # debugging print-out:

            if vars.class == Array
               vars2 = vars.join(",") 
            else
               vars2 = vars
            end

            values = self.rawdata.unpack(packing)
            vars.each { |key|
               self[key] = values.shift
            }
            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

   self
end

Instance Attribute Details

#dataEndXObject (readonly)

debugging only



1144
1145
1146
# File 'lib/id3.rb', line 1144

def dataEndX
  @dataEndX
end

#dataStartXObject (readonly)

debugging only



1144
1145
1146
# File 'lib/id3.rb', line 1144

def dataStartX
  @dataStartX
end

#headerStartXObject (readonly)

debugging only



1144
1145
1146
# File 'lib/id3.rb', line 1144

def headerStartX
  @headerStartX
end

#nameObject (readonly)

Returns the value of attribute name.



1143
1144
1145
# File 'lib/id3.rb', line 1143

def name
  @name
end

#rawdataObject (readonly)

debugging only



1144
1145
1146
# File 'lib/id3.rb', line 1144

def rawdata
  @rawdata
end

#rawheaderObject (readonly)

debugging only



1144
1145
1146
# File 'lib/id3.rb', line 1144

def rawheader
  @rawheader
end

#versionObject (readonly)

Returns the value of attribute version.



1143
1144
1145
# File 'lib/id3.rb', line 1143

def version
  @version
end

Instance Method Details

#old_initObject




1153
# File 'lib/id3.rb', line 1153

alias old_init initialize

#rawObject


return the complete raw frame



1149
1150
1151
# File 'lib/id3.rb', line 1149

def raw
  return @rawheader + @rawdata
end