Example #1
0
void Ogg::File::writePacket(unsigned int i, const ByteVector &packet)
{
    if(!readPages(i)) {
        debug("Ogg::File::writePacket() -- Could not find the requested packet.");
        return;
    }

    // Look for the pages where the requested packet should belong to.

    List<Page *>::ConstIterator it = d->pages.begin();
    while((*it)->containsPacket(i) == Page::DoesNotContainPacket)
        ++it;

    const Page *firstPage = *it;

    while(nextPacketIndex(*it) <= i)
        ++it;

    const Page *lastPage = *it;

    // Replace the requested packet and create new pages to replace the located pages.

    ByteVectorList packets = firstPage->packets();
    packets[i - firstPage->firstPacketIndex()] = packet;

    if(firstPage != lastPage && lastPage->packetCount() > 2) {
        ByteVectorList lastPagePackets = lastPage->packets();
        lastPagePackets.erase(lastPagePackets.begin());
        packets.append(lastPagePackets);
    }

    // TODO: This pagination method isn't accurate for what's being done here.
    // This should account for real possibilities like non-aligned packets and such.

    const List<Page *> pages = Page::paginate(packets,
                               Page::SinglePagePerGroup,
                               firstPage->header()->streamSerialNumber(),
                               firstPage->pageSequenceNumber(),
                               firstPage->header()->firstPacketContinued(),
                               lastPage->header()->lastPacketCompleted());

    // Write the pages.

    ByteVector data;
    for(it = pages.begin(); it != pages.end(); ++it)
        data.append((*it)->render());

    const unsigned long originalOffset = firstPage->fileOffset();
    const unsigned long originalLength = lastPage->fileOffset() + lastPage->size() - originalOffset;

    insert(data, originalOffset, originalLength);

    // Renumber the following pages if the pages have been split or merged.

    const int numberOfNewPages
        = pages.back()->pageSequenceNumber() - lastPage->pageSequenceNumber();

    if(numberOfNewPages != 0) {
        long pageOffset = originalOffset + data.size();

        while(true) {
            Page page(this, pageOffset);
            if(!page.header()->isValid())
                break;

            page.setPageSequenceNumber(page.pageSequenceNumber() + numberOfNewPages);
            const ByteVector data = page.render();

            seek(pageOffset + 18);
            writeBlock(data.mid(18, 8));

            if(page.header()->lastPageOfStream())
                break;

            pageOffset += page.size();
        }
    }

    // Discard all the pages to keep them up-to-date by fetching them again.

    d->pages.clear();
}