Example #1
0
    def parse_frames(self):
        """ Recursively Parse Frames """
        read = 0
        readframes = 0
        
        while read < self.tag["size"]:
            framedata = self.get_next_frame(self.tag["size"] - read)
            if framedata:
                try:
                    read += len(framedata)
                    if self.version == '2.2':
                        frame = ID3v2_2_Frame(frame=framedata)
                    elif self.version == '2.3':
                        frame = ID3v2_3_Frame(frame=framedata)
                    elif self.version == '2.4':
                        frame = ID3v2_4_Frame(frame=framedata)
                    readframes += 1
                    self.frames.append(frame)
                except ID3Exception:
                    pass # ignore unrecognised frames
            else:
                self.tag["padding"] = self._read_null_bytes()
                debug("NULL Padding: %d" % self.tag["padding"])
                break

        # do a sanity check on the size/padding
        if not self.tag.has_key("padding"):
            self.tag["padding"] = 0
            
        if self.tag["size"] != read + self.tag["padding"]:
            self.tag["size"] = read + self.tag["padding"]
            
        return len(self.frames)
Example #2
0
    def x_comm(self):
        """
        extract comment field

        sets: encoding, lang, shortcomment, longcomment
        """
        data = self.rawdata
        self.encoding = encodings[ord(data[0])]
        self.language = data[1:4]
        self.shortcomment = ''
        self.longcomment = ''

        if is_double_byte(self.encoding):
            for i in range(4,len(data)-1):
                if data[i:i+2] == '\x00\x00':
                    self.shortcomment = data[4:i].strip('\x00')
                    self.longcomment = data[i+2:].strip('\x00')
                    break
        else:
            for i in range(4,len(data)):
                if data[i] == '\x00':
                    self.shortcomment = data[4:i].strip('\x00')
                    self.longcomment = data[i+1:].strip('\x00')
                    break
                
        debug('Read Field: %s Len: %d Enc: %s Lang: %s Comm: %s' %
              (self.fid, self.length, self.encoding, self.language,
               str([self.shortcomment, self.longcomment])))
Example #3
0
    def x_text(self):
        """
        Extract Text Fields

        @todo: handle multiple strings seperated by \x00

        sets: encoding, strings
        """
        data = self.rawdata
        self.encoding = encodings[ord(data[0])]
        rawtext = data[1:]
        
        if normalize_encoding(self.encoding) == 'latin_1':
            text = rawtext
            self.strings = text.split('\x00')
        else:
            text = rawtext.decode(self.encoding)
            if is_double_byte(self.encoding):
                self.strings = text.split('\x00\x00')               
            else:
                self.strings = text.split('\x00')
                
        try:
            dummy = text.encode('utf_8')
            debug('Read Field: %s Len: %d Enc: %s Text: %s' %
                   (self.fid, self.length, self.encoding, str([text])))
        except UnicodeDecodeError:
            debug('Read Field: %s Len: %d Enc: %s Text: %s (Err)' %
                   (self.fid, self.length, self.encoding, str([text])))
Example #4
0
    def x_geob(self):
        """
        Extract GEOB

        set: encoding, mimetype, filename, desc, obj
        """
        data = self.rawdata
        self.encoding = encodings[ord(data[0])]
        self.mimetype = ''
        self.filename = ''
        self.desc = ''
        self.obj = ''
        
        for i in range(1,len(data)):
            if data[i] == '\x00':
                self.mimetype = data[1:i]
                break

        if not self.mimetype:
            raise ID3FrameException("Unable to extract GEOB. Missing mimetype")

        # FIXME: because filename and desc are optional, we should be
        #        smarter about splitting
        if is_double_byte(self.encoding):
            for i in range(len(self.mimetype)+2,len(data)-1):
                if data[i:i+2] == '\x00\x00':
                    self.filename = data[len(self.mimetype)+2:i]
                    ptr = len(self.mimetype) + len(self.filename) + 4
                    break
        else:
            for i in range(len(self.mimetype)+2,len(data)-1):
                if data[i] == '\x00':
                    self.filename = data[len(self.mimetype)+2:i]
                    ptr = len(self.mimetype) + len(self.filename) + 3
                    break

        if is_double_byte(self.encoding):
            for i in range(ptr,len(data)-1):
                if data[i:i+2] == '\x00\x00':
                    self.desc = data[ptr:i]
                    self.obj = data[i+2:]
                    break
        else:
            for i in range(ptr,len(data)-1):
                if data[i] == '\x00':
                    self.desc = data[ptr:i]
                    self.obj = data[i+1:]
                    break

        debug("Read Field: %s Len: %d Enc: %s Mime: %s Filename: %s Desc: %s ObjLen: %d" %
               (self.fid, self.length, self.encoding, self.mimetype,
                self.filename, self.desc, len(self.obj)))
Example #5
0
    def x_pcnt(self):
        """
        Extract Play Count

        sets: counter
        """
        data = self.rawdata
        bytes = self.length
        counter = 0
        if bytes == 4:
            counter = struct.unpack('!I',data)[0]
        else:
            for i in range(0,bytes):
                counter += struct.unpack('B',data[i]) * pow(256,i)
                
        debug('Read Field: %s Len: %d Count: %d' % (self.fid, bytes, counter))
        self.counter = counter
Example #6
0
    def x_apic(self):
        """
        Extract APIC

        set: encoding, mimetype, desc, pict, picttype
        """
        data = self.rawdata
        self.encoding = encodings[ord(data[0])]
        self.mimetype = ''
        self.desc = ''
        self.pict = ''
        self.picttype = 0

        # get mime type (must be latin-1)
        imgtype = data[1:4]
        if not imgtype:
            raise ID3FrameException("APIC extraction failed. Missing mimetype")

        if imgtype not in ID3V2_2_FRAME_IMAGE_FORMAT_TO_MIME_TYPE.keys():
            raise ID3FrameException("Unrecognised mime-type")            
        else:
            self.mimetype = ID3V2_2_FRAME_IMAGE_FORMAT_TO_MIME_TYPE[imgtype]

        picttype = ord(data[len(imgtype) + 1])

        # get picture description
        for i in range(len(imgtype) + 2, len(data) - 1):
            print [data[i:i+3]]
            if data[i] == '\x00':
                self.desc = data[len(imgtype)+2:i]
                if data[i+1] == '\x00':
                    self.pict = data[i+2:]
                else:
                    self.pict = data[i+1:]
                break
                    
        debug('Read Field: %s Len: %d PicType: %d Mime: %s Desc: %s PicLen: %d' % 
               (self.fid, self.length, self.picttype, self.mimetype,
                self.desc, len(self.pict)))
Example #7
0
    def parse_header(self):
        """
        Parse Header of the file

        """
        self.f.seek(0)
        data = self.f.read(ID3V2_FILE_HEADER_LENGTH)
        if len(data) != ID3V2_FILE_HEADER_LENGTH:
            raise ID3HeaderInvalidException("ID3 tag header is incomplete")
        
        self.tag = {}
        self.frames = []
        id3, ver, flags, rawsize = struct.unpack("!3sHB4s", data)
        
        if id3 != "ID3":
            raise ID3HeaderInvalidException("ID3v2 header not found")

        self.tag["size"] = unsyncsafe(rawsize)
        # NOTE: size  = excluding header + footer
        version = '2.%d' % (ver >> 8)
        if version not in self.supported:
            raise ID3NotImplementedException("version %s not supported" % \
                                             version)
        else:
            self.version = version
            
        if self.version in ('2.4', '2.3'):
            for flagname, bit in ID3V2_3_TAG_HEADER_FLAGS:
                self.tag[flagname] = (flags >> bit) & 0x01
        elif self.version == '2.2':
            for flagname, bit in ID3V2_2_TAG_HEADER_FLAGS:
                self.tag[flagname] = (flags >> bit) & 0x01

        if self.tag.has_key("ext") and self.tag["ext"]:
            self.parse_ext_header()
    
        debug(self.tag)
Example #8
0
    def x_apic(self):
        """
        Extract APIC

        set: encoding, mimetype, desc, pict, picttype
        """
        data = self.rawdata
        self.encoding = encodings[ord(data[0])]
        self.mimetype = ''
        self.desc = ''
        self.pict = ''
        self.picttype = 0

        # get mime type (must be latin-1)
        for i in range(1,len(data)):
            if data[i] == '\x00':
                self.mimetype = data[1:i]
                break

        if not self.mimetype:
            raise ID3FrameException("APIC extraction failed. Missing mimetype")

        picttype = ord(data[len(self.mimetype) + 2])

        # get picture description
        for i in range(len(self.mimetype) + 2, len(data)-1):
            if data[i] == '\x00':
                self.desc = data[len(self.mimetype)+2:i]
                if data[i+1] == '\x00':
                    self.pict = data[i+2:]
                else:
                    self.pict = data[i+1:]
                break

        debug('Read Field: %s Len: %d PicType: %d Mime: %s Desc: %s PicLen: %d' % 
               (self.fid, self.length, self.picttype, self.mimetype,
                self.desc, len(self.pict)))
Example #9
0
    def x_wxxx(self):
        """
        Extract URL
        
        set: encoding, desc, url
        """
        data = self.rawdata
        self.encoding = encodings[ord(data[0])]
        if is_double_byte(self.encoding):
            for i in range(1,len(data)-1):
                if data[i:i+2] == '\x00\x00':
                    self.desc = data[1:i]
                    self.url = data[i+2:]
                    break
        else:
            for i in range(1,len(data)):
                if data[i] == '\x00':
                    self.desc = data[1:i]
                    self.url = data[i+1:]
                    break

        debug("Read field: %s Len: %s Enc: %s Desc: %s URL: %s" %
               (self.fid, self.length, self.encoding,
                self.desc, str([self.url])))
Example #10
0
 def x_url(self):
     debug("Read Field: %s Len: %d Data: %s" %
            (self.fid, self.length, [self.rawdata]))
     return