def test_replace_continued(self): # take a partial packet and replace it with a new page # replace() should make it spanning again fileobj = BytesIO() pages = [OggPage(), OggPage()] pages[0].serial = 1 pages[0].sequence = 0 pages[0].complete = False pages[0].packets = [b"foo"] pages[1].serial = 1 pages[1].sequence = 1 pages[1].continued = True pages[1].packets = [b"bar"] fileobj = BytesIO() for page in pages: fileobj.write(page.write()) fileobj.seek(0, 0) pages_from_file = [OggPage(fileobj), OggPage(fileobj)] self.assertEqual(OggPage.to_packets(pages_from_file), [b"foobar"]) packets_part = OggPage.to_packets([pages_from_file[0]]) self.assertEqual(packets_part, [b"foo"]) new_pages = OggPage.from_packets([b"quuux"]) OggPage.replace(fileobj, [pages_from_file[0]], new_pages) fileobj.seek(0, 0) written = OggPage.to_packets([OggPage(fileobj), OggPage(fileobj)]) self.assertEquals(written, [b"quuuxbar"])
def _inject(self, fileobj): """Write tag data into the Speex comment packet/page.""" fileobj.seek(0) # Find the first header page, with the stream info. # Use it to get the serial number. page = OggPage(fileobj) while not page.packets[0].startswith("Speex "): page = OggPage(fileobj) # Look for the next page with that serial number, it'll start # the comment packet. serial = page.serial page = OggPage(fileobj) while page.serial != serial: page = OggPage(fileobj) # Then find all the pages with the comment packet. old_pages = [page] while not (old_pages[-1].complete or len(old_pages[-1].packets) > 1): page = OggPage(fileobj) if page.serial == old_pages[0].serial: old_pages.append(page) packets = OggPage.to_packets(old_pages, strict=False) # Set the new comment packet. packets[0] = self.write(framing=False) new_pages = OggPage.from_packets(packets, old_pages[0].sequence) OggPage.replace(fileobj, old_pages, new_pages)
def _inject(self, fileobj, padding_func): """Write tag data into the Theora comment packet/page.""" fileobj.seek(0) page = OggPage(fileobj) while not page.packets[0].startswith(b"\x81theora"): page = OggPage(fileobj) old_pages = [page] while not (old_pages[-1].complete or len(old_pages[-1].packets) > 1): page = OggPage(fileobj) if page.serial == old_pages[0].serial: old_pages.append(page) packets = OggPage.to_packets(old_pages, strict=False) content_size = get_size(fileobj) - len(packets[0]) # approx vcomment_data = b"\x81theora" + self.write(framing=False) padding_left = len(packets[0]) - len(vcomment_data) info = PaddingInfo(padding_left, content_size) new_padding = info._get_padding(padding_func) packets[0] = vcomment_data + b"\x00" * new_padding new_pages = OggPage._from_packets_try_preserve(packets, old_pages) OggPage.replace(fileobj, old_pages, new_pages)
def _inject(self, fileobj): """Write tag data into the FLAC Vorbis comment packet/page.""" # Ogg FLAC has no convenient data marker like Vorbis, but the # second packet - and second page - must be the comment data. fileobj.seek(0) page = OggPage(fileobj) while not page.packets[0].startswith("\x7FFLAC"): page = OggPage(fileobj) first_page = page while not (page.sequence == 1 and page.serial == first_page.serial): page = OggPage(fileobj) old_pages = [page] while not (old_pages[-1].complete or len(old_pages[-1].packets) > 1): page = OggPage(fileobj) if page.serial == first_page.serial: old_pages.append(page) packets = OggPage.to_packets(old_pages, strict=False) # Set the new comment block. data = self.write() data = packets[0][0] + struct.pack(">I", len(data))[-3:] + data packets[0] = data new_pages = OggPage.from_packets(packets, old_pages[0].sequence) OggPage.replace(fileobj, old_pages, new_pages)
def _inject(self, fileobj, padding_func): """Write tag data into the Theora comment packet/page.""" fileobj.seek(0) page = OggPage(fileobj) while not page.packets or \ not page.packets[0].startswith(b"\x81theora"): page = OggPage(fileobj) old_pages = [page] while not (old_pages[-1].complete or len(old_pages[-1].packets) > 1): page = OggPage(fileobj) if page.serial == old_pages[0].serial: old_pages.append(page) packets = OggPage.to_packets(old_pages, strict=False) content_size = get_size(fileobj) - len(packets[0]) # approx vcomment_data = b"\x81theora" + self.write(framing=False) padding_left = len(packets[0]) - len(vcomment_data) info = PaddingInfo(padding_left, content_size) new_padding = info._get_padding(padding_func) packets[0] = vcomment_data + b"\x00" * new_padding new_pages = OggPage._from_packets_try_preserve(packets, old_pages) OggPage.replace(fileobj, old_pages, new_pages)
def _inject(self, fileobj): """Write tag data into the Speex comment packet/page.""" fileobj.seek(0) # Find the first header page, with the stream info. # Use it to get the serial number. page = OggPage(fileobj) while not page.packets[0].startswith(b"Speex "): page = OggPage(fileobj) # Look for the next page with that serial number, it'll start # the comment packet. serial = page.serial page = OggPage(fileobj) while page.serial != serial: page = OggPage(fileobj) # Then find all the pages with the comment packet. old_pages = [page] while not (old_pages[-1].complete or len(old_pages[-1].packets) > 1): page = OggPage(fileobj) if page.serial == old_pages[0].serial: old_pages.append(page) packets = OggPage.to_packets(old_pages, strict=False) # Set the new comment packet. packets[0] = self.write(framing=False) new_pages = OggPage.from_packets(packets, old_pages[0].sequence) OggPage.replace(fileobj, old_pages, new_pages)
def _inject(self, fileobj, padding_func): """Write tag data into the Vorbis comment packet/page.""" # Find the old pages in the file; we'll need to remove them, # plus grab any stray setup packet data out of them. fileobj.seek(0) page = OggPage(fileobj) while not page.packets[0].startswith(b"\x03vorbis"): page = OggPage(fileobj) old_pages = [page] while not (old_pages[-1].complete or len(old_pages[-1].packets) > 1): page = OggPage(fileobj) if page.serial == old_pages[0].serial: old_pages.append(page) packets = OggPage.to_packets(old_pages, strict=False) content_size = get_size(fileobj) - len(packets[0]) # approx vcomment_data = b"\x03vorbis" + self.write() padding_left = len(packets[0]) - len(vcomment_data) info = PaddingInfo(padding_left, content_size) new_padding = info._get_padding(padding_func) # Set the new comment packet. packets[0] = vcomment_data + b"\x00" * new_padding new_pages = OggPage._from_packets_try_preserve(packets, old_pages) OggPage.replace(fileobj, old_pages, new_pages)
def _inject(self, fileobj): """Write tag data into the FLAC Vorbis comment packet/page.""" # Ogg FLAC has no convenient data marker like Vorbis, but the # second packet - and second page - must be the comment data. fileobj.seek(0) page = OggPage(fileobj) while not page.packets[0].startswith(b"\x7FFLAC"): page = OggPage(fileobj) first_page = page while not (page.sequence == 1 and page.serial == first_page.serial): page = OggPage(fileobj) old_pages = [page] while not (old_pages[-1].complete or len(old_pages[-1].packets) > 1): page = OggPage(fileobj) if page.serial == first_page.serial: old_pages.append(page) packets = OggPage.to_packets(old_pages, strict=False) # Set the new comment block. data = self.write() data = bytes((packets[0][0],)) + struct.pack(">I", len(data))[-3:] + data packets[0] = data new_pages = OggPage.from_packets(packets, old_pages[0].sequence) OggPage.replace(fileobj, old_pages, new_pages)
def _inject(self, fileobj): fileobj.seek(0) info = OggOpusInfo(fileobj) old_pages = self.__get_comment_pages(fileobj, info) packets = OggPage.to_packets(old_pages) packets[0] = "OpusTags" + self.write(framing=False) new_pages = OggPage.from_packets(packets, old_pages[0].sequence) OggPage.replace(fileobj, old_pages, new_pages)
def _inject(self, fileobj): fileobj.seek(0) info = OggOpusInfo(fileobj) old_pages = self.__get_comment_pages(fileobj, info) packets = OggPage.to_packets(old_pages) packets[0] = b"OpusTags" + self.write(framing=False) new_pages = OggPage.from_packets(packets, old_pages[0].sequence) OggPage.replace(fileobj, old_pages, new_pages)
def test_replace_fast_path(self): # create interleaved pages fileobj = BytesIO() pages = [OggPage(), OggPage(), OggPage()] pages[0].serial = 42 pages[0].sequence = 0 pages[0].packets = [b"foo"] pages[1].serial = 24 pages[1].sequence = 0 pages[1].packets = [b"bar"] pages[2].serial = 42 pages[2].sequence = 1 pages[2].packets = [b"baz"] for page in pages: fileobj.write(page.write()) fileobj.seek(0, 0) pages_from_file = [ OggPage(fileobj), OggPage(fileobj), OggPage(fileobj) ] old_pages = [pages_from_file[0], pages_from_file[2]] packets = OggPage.to_packets(old_pages, strict=True) self.assertEqual(packets, [b"foo", b"baz"]) new_packets = [b"111", b"222"] new_pages = OggPage._from_packets_try_preserve(new_packets, old_pages) self.assertEqual(len(new_pages), 2) # remove insert_bytes, so we can be sure the fast path was taken old_insert_bytes = _util.insert_bytes _util.insert_bytes = None try: OggPage.replace(fileobj, old_pages, new_pages) finally: _util.insert_bytes = old_insert_bytes # validate that the new data was written and the other pages # are untouched fileobj.seek(0, 0) pages_from_file = [ OggPage(fileobj), OggPage(fileobj), OggPage(fileobj) ] packets = OggPage.to_packets([pages_from_file[0], pages_from_file[2]], strict=True) self.assertEqual(packets, [b"111", b"222"]) packets = OggPage.to_packets([pages_from_file[1]], strict=True) self.assertEqual(packets, [b"bar"])
def test_replace_fast_path(self): # create interleaved pages fileobj = BytesIO() pages = [OggPage(), OggPage(), OggPage()] pages[0].serial = 42 pages[0].sequence = 0 pages[0].packets = [b"foo"] pages[1].serial = 24 pages[1].sequence = 0 pages[1].packets = [b"bar"] pages[2].serial = 42 pages[2].sequence = 1 pages[2].packets = [b"baz"] for page in pages: fileobj.write(page.write()) fileobj.seek(0, 0) pages_from_file = [OggPage(fileobj), OggPage(fileobj), OggPage(fileobj)] old_pages = [pages_from_file[0], pages_from_file[2]] packets = OggPage.to_packets(old_pages, strict=True) self.assertEqual(packets, [b"foo", b"baz"]) new_packets = [b"111", b"222"] new_pages = OggPage._from_packets_try_preserve(new_packets, old_pages) self.assertEqual(len(new_pages), 2) # remove insert_bytes, so we can be sure the fast path was taken old_insert_bytes = _util.insert_bytes _util.insert_bytes = None try: OggPage.replace(fileobj, old_pages, new_pages) finally: _util.insert_bytes = old_insert_bytes # validate that the new data was written and the other pages # are untouched fileobj.seek(0, 0) pages_from_file = [OggPage(fileobj), OggPage(fileobj), OggPage(fileobj)] packets = OggPage.to_packets( [pages_from_file[0], pages_from_file[2]], strict=True) self.assertEqual(packets, [b"111", b"222"]) packets = OggPage.to_packets([pages_from_file[1]], strict=True) self.assertEqual(packets, [b"bar"])
def _inject(self, fileobj): """Write tag data into the Theora comment packet/page.""" fileobj.seek(0) page = OggPage(fileobj) while not page.packets[0].startswith("\x81theora"): page = OggPage(fileobj) old_pages = [page] while not (old_pages[-1].complete or len(old_pages[-1].packets) > 1): page = OggPage(fileobj) if page.serial == old_pages[0].serial: old_pages.append(page) packets = OggPage.to_packets(old_pages, strict=False) packets[0] = "\x81theora" + self.write(framing=False) new_pages = OggPage.from_packets(packets, old_pages[0].sequence) OggPage.replace(fileobj, old_pages, new_pages)
def _inject(self, fileobj, padding_func): fileobj.seek(0) info = OggOpusInfo(fileobj) old_pages = self.__get_comment_pages(fileobj, info) packets = OggPage.to_packets(old_pages) vcomment_data = b"OpusTags" + self.write(framing=False) if self._pad_data: # if we have padding data to preserver we can't add more padding # as long as we don't know the structure of what follows packets[0] = vcomment_data + self._pad_data else: content_size = get_size(fileobj) - len(packets[0]) # approx padding_left = len(packets[0]) - len(vcomment_data) info = PaddingInfo(padding_left, content_size) new_padding = info._get_padding(padding_func) packets[0] = vcomment_data + b"\x00" * new_padding new_pages = OggPage._from_packets_try_preserve(packets, old_pages) OggPage.replace(fileobj, old_pages, new_pages)
def test_preserve_non_padding(self): self.audio["FOO"] = ["BAR"] self.audio.save() extra_data = b"\xde\xad\xbe\xef" with open(self.filename, "r+b") as fobj: OggPage(fobj) # header page = OggPage(fobj) data = OggPage.to_packets([page])[0] data = data.rstrip(b"\x00") + b"\x01" + extra_data new_pages = OggPage.from_packets([data], page.sequence) OggPage.replace(fobj, [page], new_pages) OggOpus(self.filename).save() with open(self.filename, "rb") as fobj: OggPage(fobj) # header page = OggPage(fobj) data = OggPage.to_packets([page])[0] self.assertTrue(data.endswith(b"\x01" + extra_data))
def test_replace(self): # create interleaved pages fileobj = BytesIO() pages = [OggPage(), OggPage(), OggPage()] pages[0].serial = 42 pages[0].sequence = 0 pages[0].packets = [b"foo"] pages[1].serial = 24 pages[1].sequence = 0 pages[1].packets = [b"bar"] pages[2].serial = 42 pages[2].sequence = 1 pages[2].packets = [b"baz"] for page in pages: fileobj.write(page.write()) fileobj.seek(0, 0) pages_from_file = [ OggPage(fileobj), OggPage(fileobj), OggPage(fileobj) ] old_pages = [pages_from_file[0], pages_from_file[2]] packets = OggPage.to_packets(old_pages, strict=True) self.assertEqual(packets, [b"foo", b"baz"]) new_packets = [b"1111", b"2222"] new_pages = OggPage.from_packets(new_packets, sequence=old_pages[0].sequence) self.assertEqual(len(new_pages), 1) OggPage.replace(fileobj, old_pages, new_pages) fileobj.seek(0, 0) first = OggPage(fileobj) self.assertEqual(first.serial, 42) self.assertEqual(OggPage.to_packets([first], strict=True), [b"1111", b"2222"]) second = OggPage(fileobj) self.assertEqual(second.serial, 24) self.assertEqual(OggPage.to_packets([second], strict=True), [b"bar"])
def _inject(self, fileobj, padding_func): """Write tag data into the Speex comment packet/page.""" fileobj.seek(0) # Find the first header page, with the stream info. # Use it to get the serial number. page = OggPage(fileobj) while not page.packets[0].startswith(b"Speex "): page = OggPage(fileobj) # Look for the next page with that serial number, it'll start # the comment packet. serial = page.serial page = OggPage(fileobj) while page.serial != serial: page = OggPage(fileobj) # Then find all the pages with the comment packet. old_pages = [page] while not (old_pages[-1].complete or len(old_pages[-1].packets) > 1): page = OggPage(fileobj) if page.serial == old_pages[0].serial: old_pages.append(page) packets = OggPage.to_packets(old_pages, strict=False) content_size = get_size(fileobj) - len(packets[0]) # approx vcomment_data = self.write(framing=False) padding_left = len(packets[0]) - len(vcomment_data) info = PaddingInfo(padding_left, content_size) new_padding = info._get_padding(padding_func) # Set the new comment packet. packets[0] = vcomment_data + b"\x00" * new_padding new_pages = OggPage._from_packets_try_preserve(packets, old_pages) OggPage.replace(fileobj, old_pages, new_pages)
def _inject(self, fileobj): """Write tag data into the Vorbis comment packet/page.""" # Find the old pages in the file; we'll need to remove them, # plus grab any stray setup packet data out of them. fileobj.seek(0) page = OggPage(fileobj) while not page.packets[0].startswith(b"\x03vorbis"): page = OggPage(fileobj) old_pages = [page] while not (old_pages[-1].complete or len(old_pages[-1].packets) > 1): page = OggPage(fileobj) if page.serial == old_pages[0].serial: old_pages.append(page) packets = OggPage.to_packets(old_pages, strict=False) # Set the new comment packet. packets[0] = b"\x03vorbis" + self.write() new_pages = OggPage.from_packets(packets, old_pages[0].sequence) OggPage.replace(fileobj, old_pages, new_pages)
def test_replace(self): # create interleaved pages fileobj = BytesIO() pages = [OggPage(), OggPage(), OggPage()] pages[0].serial = 42 pages[0].sequence = 0 pages[0].packets = [b"foo"] pages[1].serial = 24 pages[1].sequence = 0 pages[1].packets = [b"bar"] pages[2].serial = 42 pages[2].sequence = 1 pages[2].packets = [b"baz"] for page in pages: fileobj.write(page.write()) fileobj.seek(0, 0) pages_from_file = [OggPage(fileobj), OggPage(fileobj), OggPage(fileobj)] old_pages = [pages_from_file[0], pages_from_file[2]] packets = OggPage.to_packets(old_pages, strict=True) self.assertEqual(packets, [b"foo", b"baz"]) new_packets = [b"1111", b"2222"] new_pages = OggPage.from_packets(new_packets, sequence=old_pages[0].sequence) self.assertEqual(len(new_pages), 1) OggPage.replace(fileobj, old_pages, new_pages) fileobj.seek(0, 0) first = OggPage(fileobj) self.assertEqual(first.serial, 42) self.assertEqual(OggPage.to_packets([first], strict=True), [b"1111", b"2222"]) second = OggPage(fileobj) self.assertEqual(second.serial, 24) self.assertEqual(OggPage.to_packets([second], strict=True), [b"bar"])
def test_streaminfo_bad_version(self): page = OggPage(open(self.filename, "rb")).write() page = page.replace(b"\x01\x00", b"\x02\x00", 1) self.failUnlessRaises(IOError, OggFLACStreamInfo, cBytesIO(page))
def test_streaminfo_bad_marker(self): page = OggPage(open(self.filename, "rb")).write() page = page.replace(b"fLaC", b"!fLa", 1) self.failUnlessRaises(IOError, OggFLACStreamInfo, cBytesIO(page))