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(); }