def get_header(self, filename=None): f = self.fileobj f.seek(0) # Ensure we've got padding at the end, and only at the end. # If adding makes it too large, we'll scale it down later. self.metadata_blocks.append(Padding('\x00' * 1020)) MetadataBlock.group_padding(self.metadata_blocks) header = self.__check_header(f) # "fLaC" and maybe ID3 available = self.__find_audio_offset(f) - header data = MetadataBlock.writeblocks(self.metadata_blocks) if len(data) > available: # If we have too much data, see if we can reduce padding. padding = self.metadata_blocks[-1] newlength = padding.length - (len(data) - available) if newlength > 0: padding.length = newlength data = MetadataBlock.writeblocks(self.metadata_blocks) assert len(data) == available elif len(data) < available: # If we have too little data, increase padding. self.metadata_blocks[-1].length += (available - len(data)) data = MetadataBlock.writeblocks(self.metadata_blocks) assert len(data) == available self.__offset = len("fLaC" + data) return("fLaC" + data)
def __read_metadata_block(self, file): byte = ord(file.read(1)) size = to_int_be(file.read(3)) try: data = file.read(size) if len(data) != size: raise error( "file said %d bytes, read %d bytes" % (size, len(data))) block = self.METADATA_BLOCKS[byte & 0x7F](data) except (IndexError, TypeError): block = MetadataBlock(data) block.code = byte & 0x7F self.metadata_blocks.append(block) else: self.metadata_blocks.append(block) if block.code == VCFLACDict.code: if self.tags is None: self.tags = block else: raise FLACVorbisError("> 1 Vorbis comment block found") elif block.code == CueSheet.code: if self.cuesheet is None: self.cuesheet = block else: raise error("> 1 CueSheet block found") elif block.code == SeekTable.code: if self.seektable is None: self.seektable = block else: raise error("> 1 SeekTable block found") return (byte >> 7) ^ 1
def get_header(self, filename=None): f = self.fileobj f.seek(0) # Ensure we've got padding at the end, and only at the end. # If adding makes it too large, we'll scale it down later. self.metadata_blocks.append(Padding("\x00" * 1020)) MetadataBlock.group_padding(self.metadata_blocks) header = self.__check_header(f) # "fLaC" and maybe ID3 available = self.__find_audio_offset(f) - header data = MetadataBlock.writeblocks(self.metadata_blocks) if len(data) > available: # If we have too much data, see if we can reduce padding. padding = self.metadata_blocks[-1] newlength = padding.length - (len(data) - available) if newlength > 0: padding.length = newlength data = MetadataBlock.writeblocks(self.metadata_blocks) assert len(data) == available elif len(data) < available: # If we have too little data, increase padding. self.metadata_blocks[-1].length += available - len(data) data = MetadataBlock.writeblocks(self.metadata_blocks) assert len(data) == available self.__offset = len("fLaC" + data) return "fLaC" + data
def __read_metadata_block(self, file): byte = ord(file.read(1)) size = to_int_be(file.read(3)) try: data = file.read(size) if len(data) != size: raise Exception("file said %d bytes, read %d bytes" % (size, len(data))) block = self.METADATA_BLOCKS[byte & 0x7F](data) except (IndexError, TypeError): block = MetadataBlock(data) block.code = byte & 0x7F self.metadata_blocks.append(block) else: self.metadata_blocks.append(block) if block.code == VCFLACDict.code: if self.tags is None: self.tags = block else: raise FLACVorbisError("> 1 Vorbis comment block found") elif block.code == CueSheet.code: if self.cuesheet is None: self.cuesheet = block else: raise Exception("> 1 CueSheet block found") elif block.code == SeekTable.code: if self.seektable is None: self.seektable = block else: raise Exception("> 1 SeekTable block found") return (byte >> 7) ^ 1
def test_group_padding(self): blocks = [Padding(b"\x00" * 20), Padding(b"\x00" * 30), MetadataBlock(b"foobar")] blocks[-1].code = 0 length1 = len(MetadataBlock.writeblocks(blocks)) MetadataBlock.group_padding(blocks) length2 = len(MetadataBlock.writeblocks(blocks)) self.failUnlessEqual(length1, length2) self.failUnlessEqual(len(blocks), 2)
def test_group_padding(self): blocks = [Padding("\x00" * 20), Padding("\x00" * 30), MetadataBlock("foobar")] blocks[-1].code = 0 length1 = len(MetadataBlock.writeblocks(blocks)) MetadataBlock.group_padding(blocks) length2 = len(MetadataBlock.writeblocks(blocks)) self.failUnlessEqual(length1, length2) self.failUnlessEqual(len(blocks), 2)
def get_header(self, filename=None): f = self.fileobj f.seek(0) self.__check_header(f) self.__offset = self.__find_audio_offset(f) data = bytearray(b'fLaC') for block in self.metadata_blocks: if isinstance(block, Padding): continue data += MetadataBlock._writeblock(block) padding = Padding() padding.length = 1020 data += MetadataBlock._writeblock(padding, is_last=True) return bytes(data)
def test_write_read_max_size(self): class SomeBlock(MetadataBlock): code = 255 max_data_size = 2**24 - 1 block = SomeBlock(b"\x00" * max_data_size) data = MetadataBlock._writeblock(block) self.assertEqual(data[:4], b"\xff\xff\xff\xff") header_size = 4 self.assertEqual(len(data), max_data_size + header_size) block = SomeBlock(b"\x00" * (max_data_size + 1)) self.assertRaises(error, MetadataBlock._writeblock, block)
def test_write_read_max_size(self): class SomeBlock(MetadataBlock): code = 255 max_data_size = 2 ** 24 - 1 block = SomeBlock(b"\x00" * max_data_size) data = MetadataBlock._writeblock(block) self.assertEqual(data[:4], b"\xff\xff\xff\xff") header_size = 4 self.assertEqual(len(data), max_data_size + header_size) block = SomeBlock(b"\x00" * (max_data_size + 1)) self.assertRaises(error, MetadataBlock._writeblock, block)
def test_not_empty(self): self.failUnlessEqual(MetadataBlock(b"foobar").write(), b"foobar")
def test_writeblocks(self): blocks = [Padding("\x00" * 20), Padding("\x00" * 30)] self.failUnlessEqual(len(MetadataBlock.writeblocks(blocks)), 58)
def test_change(self): b = MetadataBlock("foobar") b.data = "quux" self.failUnlessEqual(b.write(), "quux")
def test_save_unknown_block(self): block = MetadataBlock("test block data") block.code = 99 self.flac.metadata_blocks.append(block) self.flac.save()
def test_too_large_padding(self): block = Padding() self.assertEqual( len(MetadataBlock._writeblocks([block], 0, 0, lambda x: 2 ** 24)), 2**24 - 1 + 4)
def test_too_large_padding(self): block = Padding() self.assertEqual( len(MetadataBlock._writeblocks([block], 0, 0, lambda x: 2**24)), 2**24 - 1 + 4)
def test_change(self): b = MetadataBlock(b"foobar") b.data = b"quux" self.failUnlessEqual(b.write(), b"quux")
def test_empty(self): self.failUnlessEqual(MetadataBlock("").write(), "")
def test_save_unknown_block(self): block = MetadataBlock(b"test block data") block.code = 99 self.flac.metadata_blocks.append(block) self.flac.save()
def test_writeblocks(self): blocks = [Padding(b"\x00" * 20), Padding(b"\x00" * 30)] self.failUnlessEqual(len(MetadataBlock.writeblocks(blocks)), 58)