Example #1
0
    def __read_extended_header(self, file):
        size = Syncsafe.decode(fileutil.xread(file, 4))
        if size < 6:
            warn("Unexpected size of ID3v2.4 extended header: {0}".format(size),
                 TagWarning)
        data = fileutil.xread(file, size - 4)

        numflags = data[0]
        if numflags != 1:
            warn("Unexpected number of ID3v2.4 extended flag bytes: {0}"
                 .format(numflags),
                 TagWarning)
        flags = data[1]
        data = data[1 + numflags:]
        if flags & 0x40:
            self.flags.add("ext:update")
            (dummy, data) = self.__read_extended_header_flag_data(data)
        if flags & 0x20:
            self.flags.add("ext:crc_present")
            (self.crc32, data) = self.__read_extended_header_flag_data(data)
            self.crc32 = Syncsafe.decode(self.crc32)
        if flags & 0x10:
            self.flags.add("ext:restrictions")
            (self.restrictions, data) = self.__read_extended_header_flag_data(
                data)
Example #2
0
 def __read_extended_header(self, file):
     (size, ext_flags, self.padding_size) = \
         struct.unpack("!IHI", fileutil.xread(file, 10))
     if size != 6 and size != 10:
         warn("Unexpected size of ID3v2.3 extended header: {0}".format(size), 
              TagWarning)
     if ext_flags & 128:
         self.flags.add("ext:crc_present")
         self.crc32 = struct.unpack("!I", fileutil.xread(file, 4))
Example #3
0
 def _read_frames(self, file):
     if "unsynchronised" in self.flags:
         ufile = UnsyncReader(file)
     else:
         ufile = file
     while file.tell() < self.offset + self.size:
         header = fileutil.xread(ufile, 6)
         if not self._is_frame_id(header[0:3]):
             break
         frameid = header[0:3].decode("ASCII")
         size = Int8.decode(header[3:6])
         data = fileutil.xread(ufile, size)
         yield (frameid, None, data)
Example #4
0
 def __read_extended_header(self, file):
     (size, ext_flags, self.padding_size) = \
         struct.unpack("!IHI", fileutil.xread(file, 10))
     if size != 6 and size != 10:
         warn("Unexpected size of ID3v2.3 extended header: {0}".format(size), 
              TagWarning)
     if ext_flags & 32768:
         if size < 10:
             warn("Extended header is too short for a CRC field: {0} bytes instead of 10".format(size),
                  TagWarning)
         else:
             self.flags.add("ext:crc_present")
             (self.crc32,) = struct.unpack("!I", fileutil.xread(file, 4))
             size -= 6
     if size > 6:
         fileutil.xread(file, size - 6)
Example #5
0
 def _read_frames(self, file):
     while file.tell() < self.offset + self.size:
         header = fileutil.xread(file, 10)
         if not self._is_frame_id(header[0:4]):
             break
         frameid = header[0:4].decode("ASCII")
         if self.ITUNES_WORKAROUND:
             # Work around iTunes frame size encoding bug.
             # Older versions of iTunes stored frame sizes as
             # straight 8bit integers, not syncsafe. 
             # (This is known to be fixed in iTunes 8.2.)
             size = Int8.decode(header[4:8])
         else:
             size = Syncsafe.decode(header[4:8])
         bflags = Int8.decode(header[8:10])
         data = fileutil.xread(file, size)
         yield (frameid, bflags, data)
Example #6
0
 def _read_frames(self, file, syncsafe_workaround=None):
     # Older versions of iTunes stored frame sizes as straight 8bit integers,
     # not syncsafe values as the spec requires.
     # (The bug is known to be fixed in iTunes 8.2.)
     #
     # To work around such an erroneous encoding, we re-read the entire tag
     # in non-syncsafe mode when we detect a frame with a bad size.
     # This heuristic does not detect all badly encoded tags;
     # it fails when the 8-bit frame size happens to be in syncsafe format.
     #
     # We could improve detection by parsing the tag both ways and see which
     # interpretation produces more frames. However, the extra effort doesn't
     # seem worthwhile to do by default.
     #
     # If you have many files with iTunes-encoded tags, you can force stagger
     # to read them in non-syncsafe mode setting the ITUNES_WORKAROUND
     # class attribute to True and let stagger reencode your tags. (Stagger
     # will never produce a 2.4 tag with non-syncsafe frame lengths.)
     if syncsafe_workaround is None:
         syncsafe_workaround = self.ITUNES_WORKAROUND
     origfpos = file.tell()
     frames = []
     while file.tell() < self.offset + self.size:
         header = fileutil.xread(file, 10)
         if not self._is_frame_id(header[0:4]):
             break
         frameid = header[0:4].decode("ASCII")
         if syncsafe_workaround:
             size = Int8.decode(header[4:8])
         else:
             try:
                 size = Syncsafe.decode(header[4:8])
             except ValueError:
                 if syncsafe_workaround:
                     raise
                 warn(
                     "Invalid syncsafe frame size; switching to 8-bit mode")
                 file.seek(origfpos)
                 return self._read_frames(file, True)
         bflags = Int8.decode(header[8:10])
         data = fileutil.xread(file, size)
         frames.append((frameid, bflags, data))
     return frames
Example #7
0
 def _read_header(self, file):
     self.offset = file.tell()
     header = fileutil.xread(file, 10)
     if header[0:5] != b"ID3\x02\00":
         raise NoTagError("ID3v2.2 header not found")
     if header[5] & 0x80:
         self.flags.add("unsynchronised")
     if header[5] & 0x40: # Compression bit is ill-defined in standard
         raise TagError("ID3v2.2 tag compression is not supported")
     if header[5] & 0x3F:
         warn("Unknown ID3v2.2 flags", TagWarning)
     self.size = Syncsafe.decode(header[6:10]) + 10
Example #8
0
 def _read_header(self, file):
     self.offset = file.tell()
     header = fileutil.xread(file, 10)
     if header[0:5] != b"ID3\x03\x00":
         raise NoTagError("ID3v2.3 header not found")
     if header[5] & 0x80:
         self.flags.add("unsynchronised")
     if header[5] & 0x40:
         self.flags.add("extended_header")
     if header[5] & 0x20:
         self.flags.add("experimental")
     if header[5] & 0x1F:
         warn("Unknown ID3v2.3 flags", TagWarning)
     self.size = Syncsafe.decode(header[6:10]) + 10
     if "extended_header" in self.flags:
         self.__read_extended_header(file)
Example #9
0
 def _read_header(self, file):
     self.offset = file.tell()
     header = fileutil.xread(file, 10)
     if header[0:5] != b"ID3\x04\x00":
         raise NoTagError("ID3v2 header not found")
     if header[5] & _TAG24_UNSYNCHRONISED:
         self.flags.add("unsynchronised")
     if header[5] & _TAG24_EXTENDED_HEADER:
         self.flags.add("extended_header")
     if header[5] & _TAG24_EXPERIMENTAL:
         self.flags.add("experimental")
     if header[5] & _TAG24_FOOTER:
         self.flags.add("footer")
     if header[5] & _TAG24_UNKNOWN_MASK:
         warn("Unknown ID3v2.4 flags", TagWarning)
     self.size = (Syncsafe.decode(header[6:10]) + 10 
                  + (10 if "footer" in self.flags else 0))
     if "extended_header" in self.flags:
         self.__read_extended_header(file)