Example #1
0
    def load(self, fh, limit_frames=None):
        """
        Load a file and extract ID3v2 data
        """
        _match_frame = self._match_frame
        self.fh = fh
        fh.seek(0)
        if fh.read(3) != 'ID3':
            return

        verinfo = fh.read(2)
        self.version = (
            2,
            ord(verinfo[0]),
            ord(verinfo[1]),
        )
        if (self.version[1] < 3):
            raise Error, "Cannot process tags with version less than 2.3.0 (This tag's version is 2.%s.%s)" % (
                self.version[1],
                self.version[2],
            )
        if (self.version[1] > 4) or (self.version[2] > 0):
            raise Error, "Cannot process tags with version greater than 2.4.0 (This tag's version is 2.%s.%s)" % (
                self.version[1],
                self.version[2],
            )

        tag_flags = binfuncs.byte2bin(fh.read(1), 8)

        self._unsync = tag_flags[0]
        self.extended_header = tag_flags[1]
        self.experimental = tag_flags[2]
        self.footer = tag_flags[3]
        assert tag_flags[4] == 0
        assert tag_flags[5] == 0
        assert tag_flags[6] == 0
        assert tag_flags[7] == 0

        if self.extended_header:
            raise Error("Don't know what to do with an extended header")

        self.tag_size = binfuncs.synchsafe2dec(fh.read(4))
        if DEBUG_LEVEL >= 1:
            print "tag version: %d.%d.%d" % self.version
            print "tag size:", self.tag_size
            print "unsync:", self.unsync

        if self.version[1] == 3 and self.unsync:
            # print self.tag_size
            tag = fh.read(self.tag_size)
            tag = binfuncs.deunsynchstr(tag)
            self.tag_size = len(tag)
            fh = StringIO.StringIO(tag)

        sizeleft = self.tag_size

        # 11 == frame header + 1 byte frame, smallest legal frame
        while sizeleft >= 11:
            frameid = fh.read(4)
            if _match_frame(frameid) or frameid in ID3v2Frames.frameTypes[
                    self.version[1]]:
                rawframesize = fh.read(4)
                if self.version[1] >= 4 and frameid != 'COM ':
                    framesize = binfuncs.synchsafe2dec(rawframesize)
                    (framesize23, ) = struct.unpack('!I', rawframesize)


#                    print "2.4: %d vs 2.3: %d" % (framesize, framesize23,)
                else:
                    (framesize, ) = struct.unpack('!I', rawframesize)

                if framesize > sizeleft + 2:
                    if self.broken_frames == 'drop':
                        #                       warnings.warn("Broken frame size in %r. Dropping rest of tag." % self.filename)
                        self.padding_size = sizeleft
                        sizeleft = 0
                        break
                    else:
                        raise BrokenFrameError(
                            "Invalid frame size %r (raw: %r).  Frame type was %r. Corrupt tag."
                            % (
                                framesize,
                                rawframesize,
                                frameid,
                            ))
                data = fh.read(framesize + 2)
                if DEBUG_LEVEL >= 2:
                    print "Raw frame: %r" % (data, )
            elif frameid == '\x00\x00\x00\x00' or frameid == 'MP3e':
                # MP3ext http://www.mutschler.de/mp3ext/ puts "MP3ext " over and over in the padding
                sizeleft -= 4
                break
            else:
                try:
                    lastframeid = self.frames[-1].id
                except IndexError:
                    lastframeid = None

                raise Error(
                    "Found garbage where I expected a Frame Id %r. Last frame was %r"
                    % (
                        frameid,
                        lastframeid,
                    ))

            try:
                if limit_frames and frameid in limit_frames:
                    self.new_frame(frameid, data)
            except BrokenFrameError, err:
                if self.broken_frames == 'drop':
                    #                   warnings.warn("Broken frame in %r. Dropping frame." % self.filename)
                    pass
                else:
                    raise
            sizeleft -= (framesize + 2 + 4 + 4)
Example #2
0
    def _parse_frame(self, data):
        flags = binfuncs.byte2bin(data[:2], 8)
        self.data = data[2:]

        if self.version[1] == 3:
            # %abc00000 %ijk00000
            self.tag_alter_preservation = flags[0]
            self.file_alter_preservation = flags[1]
            self.read_only = flags[2]
            assert flags[3] == 0
            assert flags[4] == 0
            assert flags[5] == 0
            assert flags[6] == 0
            assert flags[7] == 0
            self._compression = flags[8]
            self.encryption = flags[9]
            self.grouping_id = flags[10]
            assert flags[11] == 0
            assert flags[12] == 0
            assert flags[13] == 0
            assert flags[14] == 0
            assert flags[15] == 0
        elif self.version[1] == 4:
            # %0abc0000 %0h00kmnp
            assert flags[0] == 0
            self.tag_alter_preservation = flags[1]
            self.file_alter_preservation = flags[2]
            self.read_only = flags[3]
            assert flags[4] == 0
            assert flags[5] == 0
            assert flags[6] == 0
            assert flags[7] == 0
            assert flags[8] == 0
            self.grouping_id = flags[9]
            assert flags[10] == 0
            assert flags[11] == 0
            self._compression = flags[12]
            self.encryption = flags[13]
            self._unsynchronisation = flags[14]
            self.data_length_indicator = flags[15]
            if self._compression and not self.data_length_indicator:
                raise dnuos.id3.BrokenFrameError, "The compression flag was set but not the data_length_indicator"
        else:
            raise dnuos.id3.Error("Unsupported tag (how did we not catch this before?)")

        # these add bytes to the header
        if self.grouping_id:
            self.group_id = self.data[0]
            self.data = self.data[1:]
        if self.encryption:
            self.encryption_method = self.data[0]
            self.data = self.data[1:]
        if self.version[1] == 3 and self.compression:
            (self.true_size,) = struct.unpack('!I', self.data[:4])
            self.data = self.data[4:]
        if self.version[1] == 4 and self.data_length_indicator:
            self.true_size = binfuncs.synchsafe2dec(self.data[:4])
            self.data = self.data[4:]

        # now we post process
        if self.unsynchronisation:
            self.data = binfuncs.unsynchstr(self.data)
#        if self.encryption:
#            warnings.warn("Encrypted frame (method %r, frameid %r" % (self.encryption_method, self.frameid,))
        if self.compression:
            self.data = zlib.decompress(self.data)


        if self.true_size:
            assert len(self.data) == self.true_size, "len(data) == %d should be == %d, and should %r" % (len(self.data), self.true_size, self.__dict__)

        # now we run the subclass's data parser

        self.parse_data()
Example #3
0
    def _parse_frame(self, data):
        flags = binfuncs.byte2bin(data[:2], 8)
        self.data = data[2:]

        if self.version[1] == 3:
            # %abc00000 %ijk00000
            self.tag_alter_preservation = flags[0]
            self.file_alter_preservation = flags[1]
            self.read_only = flags[2]
            assert flags[3] == 0
            assert flags[4] == 0
            assert flags[5] == 0
            assert flags[6] == 0
            assert flags[7] == 0
            self._compression = flags[8]
            self.encryption = flags[9]
            self.grouping_id = flags[10]
            assert flags[11] == 0
            assert flags[12] == 0
            assert flags[13] == 0
            assert flags[14] == 0
            assert flags[15] == 0
        elif self.version[1] == 4:
            # %0abc0000 %0h00kmnp
            assert flags[0] == 0
            self.tag_alter_preservation = flags[1]
            self.file_alter_preservation = flags[2]
            self.read_only = flags[3]
            assert flags[4] == 0
            assert flags[5] == 0
            assert flags[6] == 0
            assert flags[7] == 0
            assert flags[8] == 0
            self.grouping_id = flags[9]
            assert flags[10] == 0
            assert flags[11] == 0
            self._compression = flags[12]
            self.encryption = flags[13]
            self._unsynchronisation = flags[14]
            self.data_length_indicator = flags[15]
            if self._compression and not self.data_length_indicator:
                raise dnuos.id3.BrokenFrameError, "The compression flag was set but not the data_length_indicator"
        else:
            raise dnuos.id3.Error(
                "Unsupported tag (how did we not catch this before?)")

        # these add bytes to the header
        if self.grouping_id:
            self.group_id = self.data[0]
            self.data = self.data[1:]
        if self.encryption:
            self.encryption_method = self.data[0]
            self.data = self.data[1:]
        if self.version[1] == 3 and self.compression:
            (self.true_size, ) = struct.unpack('!I', self.data[:4])
            self.data = self.data[4:]
        if self.version[1] == 4 and self.data_length_indicator:
            self.true_size = binfuncs.synchsafe2dec(self.data[:4])
            self.data = self.data[4:]

        # now we post process
        if self.unsynchronisation:
            self.data = binfuncs.unsynchstr(self.data)


#        if self.encryption:
#            warnings.warn("Encrypted frame (method %r, frameid %r" % (self.encryption_method, self.frameid,))
        if self.compression:
            self.data = zlib.decompress(self.data)

        if self.true_size:
            assert len(
                self.data
            ) == self.true_size, "len(data) == %d should be == %d, and should %r" % (
                len(self.data), self.true_size, self.__dict__)

        # now we run the subclass's data parser

        self.parse_data()
Example #4
0
    def load(self, fh, limit_frames=None):
        """
        Load a file and extract ID3v2 data
        """
        _match_frame = self._match_frame
        self.fh = fh
        fh.seek(0)
        if fh.read(3) != 'ID3':
            return

        verinfo = fh.read(2)
        self.version = (2,ord(verinfo[0]),ord(verinfo[1]),)
        if(self.version[1] < 3):
            raise Error, "Cannot process tags with version less than 2.3.0 (This tag's version is 2.%s.%s)" % (self.version[1],self.version[2],)
        if(self.version[1] > 4) or (self.version[2] > 0):
            raise Error, "Cannot process tags with version greater than 2.4.0 (This tag's version is 2.%s.%s)" % (self.version[1], self.version[2],)

        tag_flags = binfuncs.byte2bin(fh.read(1), 8)

        self._unsync = tag_flags[0]
        self.extended_header = tag_flags[1]
        self.experimental = tag_flags[2]
        self.footer = tag_flags[3]
        assert tag_flags[4] == 0
        assert tag_flags[5] == 0
        assert tag_flags[6] == 0
        assert tag_flags[7] == 0

        if self.extended_header:
            raise Error("Don't know what to do with an extended header")

        self.tag_size = binfuncs.synchsafe2dec(fh.read(4))
        if DEBUG_LEVEL >= 1:
            print "tag version: %d.%d.%d" % self.version
            print "tag size:", self.tag_size
            print "unsync:", self.unsync

        if self.version[1] == 3 and self.unsync:
            # print self.tag_size
            tag = fh.read(self.tag_size)
            tag = binfuncs.deunsynchstr(tag)
            self.tag_size = len(tag)
            fh = StringIO.StringIO(tag)

        sizeleft = self.tag_size

        # 11 == frame header + 1 byte frame, smallest legal frame
        while sizeleft >= 11:
            frameid = fh.read(4)
            if _match_frame(frameid) or frameid in ID3v2Frames.frameTypes[self.version[1]]:
                rawframesize = fh.read(4)
                if self.version[1] >= 4 and frameid != 'COM ':
                    framesize = binfuncs.synchsafe2dec(rawframesize)
                    (framesize23,) = struct.unpack('!I', rawframesize)
#                    print "2.4: %d vs 2.3: %d" % (framesize, framesize23,)
                else:
                    (framesize,) = struct.unpack('!I', rawframesize)



                if framesize > sizeleft + 2:
                    if self.broken_frames == 'drop':
#                       warnings.warn("Broken frame size in %r. Dropping rest of tag." % self.filename)
                        self.padding_size = sizeleft
                        sizeleft = 0
                        break
                    else:
                        raise BrokenFrameError("Invalid frame size %r (raw: %r).  Frame type was %r. Corrupt tag." % (framesize,rawframesize,frameid,))
                data = fh.read(framesize + 2)
                if DEBUG_LEVEL >= 2:
                    print "Raw frame: %r" % (data,)
            elif frameid == '\x00\x00\x00\x00' or frameid == 'MP3e':
                # MP3ext http://www.mutschler.de/mp3ext/ puts "MP3ext " over and over in the padding
                sizeleft -= 4
                break
            else:
                try:
                    lastframeid = self.frames[-1].id
                except IndexError:
                    lastframeid = None

                raise Error("Found garbage where I expected a Frame Id %r. Last frame was %r" % (frameid, lastframeid,))

            try:
                if limit_frames and frameid in limit_frames:
                    self.new_frame(frameid, data)
            except BrokenFrameError, err:
                if self.broken_frames == 'drop':
#                   warnings.warn("Broken frame in %r. Dropping frame." % self.filename)
                    pass
                else:
                    raise
            sizeleft -= (framesize + 2 + 4 + 4)