def __fill_missing(self, fileobj): fileobj.seek(self.metadata + 8) self.version = fileobj.read(4) self.size = cdata.uint_le(fileobj.read(4)) self.items = cdata.uint_le(fileobj.read(4)) self.flags = cdata.uint_le(fileobj.read(4)) if self.header is not None: self.data = self.header + 32 # If we're reading the header, the size is the header # offset + the size, which includes the footer. self.end = self.data + self.size fileobj.seek(self.end - 32, 0) if fileobj.read(8) == b"APETAGEX": self.footer = self.end - 32 elif self.footer is not None: self.end = self.footer + 32 self.data = self.end - self.size if self.flags & HAS_HEADER: self.header = self.data - 32 else: self.header = self.data else: raise APENoHeaderError("No APE tag found") # exclude the footer from size if self.footer is not None: self.size -= 32
def load(self, fileobj, errors='replace', framing=True): """Parse a Vorbis comment from a file-like object. Keyword arguments: errors: 'strict', 'replace', or 'ignore'. This affects Unicode decoding and how other malformed content is interpreted. framing -- if true, fail if a framing bit is not present Framing bits are required by the Vorbis comment specification, but are not used in FLAC Vorbis comment blocks. """ try: vendor_length = cdata.uint_le(fileobj.read(4)) self.vendor = fileobj.read(vendor_length).decode('utf-8', errors) count = cdata.uint_le(fileobj.read(4)) for i in range(count): length = cdata.uint_le(fileobj.read(4)) string = fileobj.read(length).decode('utf-8', errors) try: tag, value = string.split('=', 1) except ValueError, err: if errors == "ignore": continue elif errors == "replace": tag, value = u"unknown%d" % i, string else: raise VorbisEncodingError, str(err), sys.exc_info()[2] try: tag = tag.encode('ascii', errors) except UnicodeEncodeError: raise VorbisEncodingError, "invalid tag name %r" % tag else: if is_valid_key(tag): self.append((tag, value)) if framing and not ord(fileobj.read(1)) & 0x01: raise VorbisUnsetFrameError("framing bit was unset")
def __parse_tag(self, tag, count): fileobj = cBytesIO(tag) for i in xrange(count): size_data = fileobj.read(4) # someone writes wrong item counts if not size_data: break size = cdata.uint_le(size_data) flags = cdata.uint_le(fileobj.read(4)) # Bits 1 and 2 bits are flags, 0-3 # Bit 0 is read/write flag, ignored kind = (flags & 6) >> 1 if kind == 3: raise APEBadItemError("value type must be 0, 1, or 2") key = value = fileobj.read(1) while key[-1:] != b'\x00' and value: value = fileobj.read(1) key += value if key[-1:] == b"\x00": key = key[:-1] if PY3: try: key = key.decode("ascii") except UnicodeError as err: reraise(APEBadItemError, err, sys.exc_info()[2]) value = fileobj.read(size) value = _get_value_type(kind)._new(value) self[key] = value
def __init__(self, fileobj): header = fileobj.read(28) if len(header) != 28 or not header.startswith("wvpk"): raise WavPackHeaderError("not a WavPack file") samples = cdata.uint_le(header[12:16]) flags = cdata.uint_le(header[24:28]) self.version = cdata.short_le(header[8:10]) self.channels = bool(flags & 4) or 2 self.sample_rate = RATES[(flags >> 23) & 0xF] self.length = float(samples) / self.sample_rate
def __init__(self, fileobj): page = OggPage(fileobj) while not page.packets[0].startswith(b"Speex "): page = OggPage(fileobj) if not page.first: raise OggSpeexHeaderError( "page has ID header, but doesn't start a stream") self.sample_rate = cdata.uint_le(page.packets[0][36:40]) self.channels = cdata.uint_le(page.packets[0][48:52]) self.bitrate = max(0, cdata.int_le(page.packets[0][52:56])) self.serial = page.serial
def test_uint(self): self.failUnlessEqual(cdata.uint_le(self.ZERO(4)), 0) self.failUnlessEqual(cdata.uint_le(self.LEONE(4)), 1) self.failUnlessEqual(cdata.uint_le(self.BEONE(4)), 2 ** 32 >> 8) self.failUnlessEqual(cdata.uint_le(self.NEGONE(4)), 2 ** 32 - 1) self.assertTrue(cdata.uint_le is cdata.uint32_le) self.failUnlessEqual(cdata.uint_be(self.ZERO(4)), 0) self.failUnlessEqual(cdata.uint_be(self.LEONE(4)), 2 ** 32 >> 8) self.failUnlessEqual(cdata.uint_be(self.BEONE(4)), 1) self.failUnlessEqual(cdata.uint_be(self.NEGONE(4)), 2 ** 32 - 1) self.assertTrue(cdata.uint_be is cdata.uint32_be)
def test_uint(self): self.failUnlessEqual(cdata.uint_le(self.ZERO(4)), 0) self.failUnlessEqual(cdata.uint_le(self.LEONE(4)), 1) self.failUnlessEqual(cdata.uint_le(self.BEONE(4)), 2**32 >> 8) self.failUnlessEqual(cdata.uint_le(self.NEGONE(4)), 2**32 - 1) self.assertTrue(cdata.uint_le is cdata.uint32_le) self.failUnlessEqual(cdata.uint_be(self.ZERO(4)), 0) self.failUnlessEqual(cdata.uint_be(self.LEONE(4)), 2**32 >> 8) self.failUnlessEqual(cdata.uint_be(self.BEONE(4)), 1) self.failUnlessEqual(cdata.uint_be(self.NEGONE(4)), 2**32 - 1) self.assertTrue(cdata.uint_be is cdata.uint32_be)
def __init__(self, fileobj): header = bytearray(fileobj.read(32)) if len(header) != 32: raise MusepackHeaderError("not a Musepack file") # Skip ID3v2 tags if header[:3] == b"ID3": size = 10 + BitPaddedInt(header[6:10]) fileobj.seek(size) header = bytearray(fileobj.read(32)) if len(header) != 32: raise MusepackHeaderError("not a Musepack file") # SV7 if header.startswith(b"MP+"): self.version = header[3] & 0xF if self.version < 7: raise MusepackHeaderError("not a Musepack file") frames = cdata.uint_le(header[4:8]) flags = cdata.uint_le(header[8:12]) self.title_peak, self.title_gain = struct_unpack( "<Hh", header[12:16]) self.album_peak, self.album_gain = struct_unpack( "<Hh", header[16:20]) self.title_gain /= 100.0 self.album_gain /= 100.0 self.title_peak /= 65535.0 self.album_peak /= 65535.0 self.sample_rate = RATES[(flags >> 16) & 0x0003] self.bitrate = 0 # SV4-SV6 else: header_dword = cdata.uint_le(header[0:4]) self.version = (header_dword >> 11) & 0x03FF; if self.version < 4 or self.version > 6: raise MusepackHeaderError("not a Musepack file") self.bitrate = (header_dword >> 23) & 0x01FF; self.sample_rate = 44100 if self.version >= 5: frames = cdata.uint_le(header[4:8]) else: frames = cdata.ushort_le(header[6:8]) if self.version < 6: frames -= 1 self.channels = 2 self.length = float(frames * 1152 - 576) / self.sample_rate if not self.bitrate and self.length != 0: fileobj.seek(0, 2) self.bitrate = int(fileobj.tell() * 8 / (self.length * 1000) + 0.5)
def __init__(self, fileobj): header = bytearray(fileobj.read(32)) if len(header) != 32: raise MusepackHeaderError("not a Musepack file") # Skip ID3v2 tags if header[:3] == b"ID3": size = 10 + BitPaddedInt(header[6:10]) fileobj.seek(size) header = bytearray(fileobj.read(32)) if len(header) != 32: raise MusepackHeaderError("not a Musepack file") # SV7 if header.startswith(b"MP+"): self.version = header[3] & 0xF if self.version < 7: raise MusepackHeaderError("not a Musepack file") frames = cdata.uint_le(header[4:8]) flags = cdata.uint_le(header[8:12]) self.title_peak, self.title_gain = struct_unpack( "<Hh", header[12:16]) self.album_peak, self.album_gain = struct_unpack( "<Hh", header[16:20]) self.title_gain /= 100.0 self.album_gain /= 100.0 self.title_peak /= 65535.0 self.album_peak /= 65535.0 self.sample_rate = RATES[(flags >> 16) & 0x0003] self.bitrate = 0 # SV4-SV6 else: header_dword = cdata.uint_le(header[0:4]) self.version = (header_dword >> 11) & 0x03FF if self.version < 4 or self.version > 6: raise MusepackHeaderError("not a Musepack file") self.bitrate = (header_dword >> 23) & 0x01FF self.sample_rate = 44100 if self.version >= 5: frames = cdata.uint_le(header[4:8]) else: frames = cdata.ushort_le(header[6:8]) if self.version < 6: frames -= 1 self.channels = 2 self.length = float(frames * 1152 - 576) / self.sample_rate if not self.bitrate and self.length != 0: fileobj.seek(0, 2) self.bitrate = int(fileobj.tell() * 8 / (self.length * 1000) + 0.5)
def load(self, fileobj, errors='replace', framing=True): """Parse a Vorbis comment from a file-like object. Keyword arguments: * errors: 'strict', 'replace', or 'ignore'. This affects Unicode decoding and how other malformed content is interpreted. * framing -- if true, fail if a framing bit is not present Framing bits are required by the Vorbis comment specification, but are not used in FLAC Vorbis comment blocks. """ try: vendor_length = cdata.uint_le(fileobj.read(4)) self.vendor = fileobj.read(vendor_length).decode('utf-8', errors) count = cdata.uint_le(fileobj.read(4)) for i in xrange(count): length = cdata.uint_le(fileobj.read(4)) try: string = fileobj.read(length).decode('utf-8', errors) except (OverflowError, MemoryError): raise error("cannot read %d bytes, too large" % length) try: tag, value = string.split('=', 1) except ValueError as err: if errors == "ignore": continue elif errors == "replace": tag, value = u"unknown%d" % i, string else: reraise(VorbisEncodingError, err, sys.exc_info()[2]) try: tag = tag.encode('ascii', errors) except UnicodeEncodeError: raise VorbisEncodingError("invalid tag name %r" % tag) else: # string keys in py3k if PY3: tag = tag.decode("ascii") if is_valid_key(tag): self.append((tag, value)) if framing and not bytearray(fileobj.read(1))[0] & 0x01: raise VorbisUnsetFrameError("framing bit was unset") except (cdata.error, TypeError): raise error("file is not a valid Vorbis comment")
def load(self, fileobj, errors="replace", framing=True): """Parse a Vorbis comment from a file-like object. Keyword arguments: * errors: 'strict', 'replace', or 'ignore'. This affects Unicode decoding and how other malformed content is interpreted. * framing -- if true, fail if a framing bit is not present Framing bits are required by the Vorbis comment specification, but are not used in FLAC Vorbis comment blocks. """ try: vendor_length = cdata.uint_le(fileobj.read(4)) self.vendor = fileobj.read(vendor_length).decode("utf-8", errors) count = cdata.uint_le(fileobj.read(4)) for i in xrange(count): length = cdata.uint_le(fileobj.read(4)) try: string = fileobj.read(length).decode("utf-8", errors) except (OverflowError, MemoryError): raise error("cannot read %d bytes, too large" % length) try: tag, value = string.split("=", 1) except ValueError as err: if errors == "ignore": continue elif errors == "replace": tag, value = u"unknown%d" % i, string else: reraise(VorbisEncodingError, err, sys.exc_info()[2]) try: tag = tag.encode("ascii", errors) except UnicodeEncodeError: raise VorbisEncodingError("invalid tag name %r" % tag) else: # string keys in py3k if PY3: tag = tag.decode("ascii") if is_valid_key(tag): self.append((tag, value)) if framing and not bytearray(fileobj.read(1))[0] & 0x01: raise VorbisUnsetFrameError("framing bit was unset") except (cdata.error, TypeError): raise error("file is not a valid Vorbis comment")
def load(self, fileobj, errors='replace', framing=True): """Parse a Vorbis comment from a file-like object. Keyword arguments: errors: 'strict', 'replace', or 'ignore'. This affects Unicode decoding and how other malformed content is interpreted. framing -- if true, fail if a framing bit is not present Framing bits are required by the Vorbis comment specification, but are not used in FLAC Vorbis comment blocks. """ self.tag_data = [] try: vendor_length = cdata.uint_le(fileobj.read(4)) self.vendor = fileobj.read(vendor_length).decode('utf-8', errors) count = cdata.uint_le(fileobj.read(4)) for i in range(count): length = cdata.uint_le(fileobj.read(4)) data_offset = fileobj.tell() try: string = fileobj.read(length).decode('utf-8', errors) except (OverflowError, MemoryError): raise error("cannot read %d bytes, too large" % length) try: tag, value = string.split('=', 1) except ValueError, err: if errors == "ignore": continue elif errors == "replace": tag, value = u"unknown%d" % i, string else: raise VorbisEncodingError, str(err), sys.exc_info()[2] try: tag = tag.encode('ascii', errors) except UnicodeEncodeError: raise VorbisEncodingError, "invalid tag name %r" % tag else: if is_valid_key(tag): self.append((tag, value)) self.tag_data.append( (data_offset, length) ) # the offset is relative to the passed in fileobj, not the file if framing and not ord(fileobj.read(1)) & 0x01: raise VorbisUnsetFrameError("framing bit was unset")
def __init__(self, fileobj, offset): fileobj.seek(offset or 0) header = fileobj.read(18) if len(header) != 18 or not header.startswith("TTA"): raise TrueAudioHeaderError("TTA header not found") self.sample_rate = cdata.int_le(header[10:14]) samples = cdata.uint_le(header[14:18]) self.length = float(samples) / self.sample_rate
def __init__(self, fileobj, offset): fileobj.seek(offset or 0) header = fileobj.read(18) if len(header) != 18 or not header.startswith(b"TTA"): raise TrueAudioHeaderError("TTA header not found") self.sample_rate = cdata.int_le(header[10:14]) samples = cdata.uint_le(header[14:18]) self.length = float(samples) / self.sample_rate
def __parse_tag(self, tag, count): fileobj = StringIO(tag) for i in range(count): size = cdata.uint_le(fileobj.read(4)) flags = cdata.uint_le(fileobj.read(4)) # Bits 1 and 2 bits are flags, 0-3 # Bit 0 is read/write flag, ignored kind = (flags & 6) >> 1 if kind == 3: raise APEBadItemError("value type must be 0, 1, or 2") key = value = fileobj.read(1) while key[-1:] != '\x00' and value: value = fileobj.read(1) key += value if key[-1:] == "\x00": key = key[:-1] value = fileobj.read(size) self[key] = APEValue(value, kind)
def __parse_tag(self, tag, count): fileobj = StringIO(tag) for i in range(count): size = cdata.uint_le(fileobj.read(4)) flags = cdata.uint_le(fileobj.read(4)) # Bits 1 and 2 bits are flags, 0-3 # Bit 0 is read/write flag, ignored kind = (flags & 6) >> 1 if kind == 3: raise APEBadItemError("value type must be 0, 1, or 2") key = value = fileobj.read(1) while key[-1:] != "\x00" and value: value = fileobj.read(1) key += value if key[-1:] == "\x00": key = key[:-1] value = fileobj.read(size) self[key] = APEValue(value, kind)
def __parse_sv467(self, fileobj): fileobj.seek(-4, 1) header = fileobj.read(32) if len(header) != 32: raise MusepackHeaderError("not a Musepack file") # SV7 if header.startswith(b"MP+"): self.version = bytearray(header)[3] & 0xF if self.version < 7: raise MusepackHeaderError("not a Musepack file") frames = cdata.uint_le(header[4:8]) flags = cdata.uint_le(header[8:12]) self.title_peak, self.title_gain = struct.unpack( "<Hh", header[12:16]) self.album_peak, self.album_gain = struct.unpack( "<Hh", header[16:20]) self.title_gain /= 100.0 self.album_gain /= 100.0 self.title_peak /= 65535.0 self.album_peak /= 65535.0 self.sample_rate = RATES[(flags >> 16) & 0x0003] self.bitrate = 0 # SV4-SV6 else: header_dword = cdata.uint_le(header[0:4]) self.version = (header_dword >> 11) & 0x03FF if self.version < 4 or self.version > 6: raise MusepackHeaderError("not a Musepack file") self.bitrate = (header_dword >> 23) & 0x01FF self.sample_rate = 44100 if self.version >= 5: frames = cdata.uint_le(header[4:8]) else: frames = cdata.ushort_le(header[6:8]) if self.version < 6: frames -= 1 self.channels = 2 self.length = float(frames * 1152 - 576) / self.sample_rate
def load(self): data = self.fileobj.read(FormatChunk.CHUNK_SIZE) if len(data) != FormatChunk.CHUNK_SIZE: raise error("DSF chunk truncated") self.chunk_header = data[0:4] if self.chunk_header != b"fmt ": raise error("DSF fmt header not found") self.chunk_size = cdata.ulonglong_le(data[4:12]) if self.chunk_size != FormatChunk.CHUNK_SIZE: raise error("DSF dsd header size mismatch") self.format_version = cdata.uint_le(data[12:16]) if self.format_version != FormatChunk.VERSION: raise error("Unsupported format version") self.format_id = cdata.uint_le(data[16:20]) if self.format_id != FormatChunk.FORMAT_DSD_RAW: raise error("Unsupported format ID") self.channel_type = cdata.uint_le(data[20:24]) self.channel_num = cdata.uint_le(data[24:28]) self.sampling_frequency = cdata.uint_le(data[28:32]) self.bits_per_sample = cdata.uint_le(data[32:36]) self.sample_count = cdata.ulonglong_le(data[36:44])
def __init__(self, fileobj, offset=None): # Warning, offset ignored! fileobj.seek(0) dsd_header = fileobj.read(28) if len(dsd_header) != 28 or not dsd_header.startswith("DSD "): raise DSFHeaderError("DSF dsd header not found") self.file_size = cdata.ulonglong_le(dsd_header[12:20]) self.id3_location = cdata.ulonglong_le(dsd_header[20:28]) fmt_header = fileobj.read(52) if len(fmt_header) != 52 or not fmt_header.startswith("fmt "): raise DSFHeaderError("DSF fmt header not found") self.format_version = cdata.uint_le(fmt_header[12:16]) self.format_id = cdata.uint_le(fmt_header[16:20]) self.channel_type = cdata.uint_le(fmt_header[20:24]) self.channel_num = cdata.uint_le(fmt_header[24:28]) self.sample_rate = cdata.uint_le(fmt_header[28:32]) self.bits_per_sample = cdata.uint_le(fmt_header[32:36]) samples = cdata.ulonglong_le(fmt_header[36:44]) self.length = float(samples) / self.sample_rate
def from_fileobj(cls, fileobj): """A new _WavPackHeader or raises WavPackHeaderError""" header = fileobj.read(32) if len(header) != 32 or not header.startswith(b"wvpk"): raise WavPackHeaderError("not a WavPack header: %r" % header) block_size = cdata.uint_le(header[4:8]) version = cdata.ushort_le(header[8:10]) track_no = ord(header[10:11]) index_no = ord(header[11:12]) samples = cdata.uint_le(header[12:16]) if samples == 2 ** 32 - 1: samples = -1 block_index = cdata.uint_le(header[16:20]) block_samples = cdata.uint_le(header[20:24]) flags = cdata.uint_le(header[24:28]) crc = cdata.uint_le(header[28:32]) return _WavPackHeader(block_size, version, track_no, index_no, samples, block_index, block_samples, flags, crc)
def from_fileobj(cls, fileobj): """A new _WavPackHeader or raises WavPackHeaderError""" header = fileobj.read(32) if len(header) != 32 or not header.startswith(b"wvpk"): raise WavPackHeaderError("not a WavPack header: %r" % header) block_size = cdata.uint_le(header[4:8]) version = cdata.ushort_le(header[8:10]) track_no = ord(header[10:11]) index_no = ord(header[11:12]) samples = cdata.uint_le(header[12:16]) if samples == 2**32 - 1: samples = -1 block_index = cdata.uint_le(header[16:20]) block_samples = cdata.uint_le(header[20:24]) flags = cdata.uint_le(header[24:28]) crc = cdata.uint_le(header[28:32]) return _WavPackHeader(block_size, version, track_no, index_no, samples, block_index, block_samples, flags, crc)
def test_uint_le(self): self.failUnlessEqual(cdata.uint_le(self.ZERO), 0) self.failUnlessEqual(cdata.uint_le(self.LEONE), 1) self.failUnlessEqual(cdata.uint_le(self.BEONE), 16777216) self.failUnlessEqual(cdata.uint_le(self.NEGONE), 2**32-1)
def test_uint_le(self): self.failUnlessEqual(cdata.uint_le(self.ZERO), 0) self.failUnlessEqual(cdata.uint_le(self.LEONE), 1) self.failUnlessEqual(cdata.uint_le(self.BEONE), 16777216) self.failUnlessEqual(cdata.uint_le(self.NEGONE), 2**32 - 1)