bool YaffsControl::readImage() { int result = 0; memset(&mReadInfo, 0, sizeof(YaffsReadInfo)); if (mImageFile) { while (result == 0) { result = readPage(); if (result == -1) { if (feof(mImageFile)) { mReadInfo.eofHasIncompletePage = true; result = 1; } break; } processPage(); } } mReadInfo.result = (result == 1); mObserver->readComplete(); return mReadInfo.result; }
int copyPdfFile( soPdfFile* inFile, soPdfFile* outFile ) { fz_error *error; int pageTreeNum, pageTreeGen; assert(inFile != NULL); assert(outFile != NULL); // // Process every page in the source file // { printf("\nProcessing input page : "); for (int pageNo = 0; pageNo < pdf_getpagecount(inFile->pageTree); pageNo++) { displayPageNumber(pageNo + 1, !pageNo); // Get the page object from the source fz_obj *pageRef = inFile->pageTree->pref[pageNo]; fz_obj *pageObj = pdf_getpageobject(inFile->pageTree, pageNo); // // Process the page. Each page can be split into up-to 3 pages // fz_rect bbRect[3]; error = processPage(inFile, pageNo, bbRect, 3); if (error) return soPdfError(error); for (int ctr = 0; ctr < 3; ctr++) { // Check if this was a blank page if (fz_isemptyrect(bbRect[ctr])) break; // // copy the source page dictionary entry. The way this is done is basically // by making a copy of the page dict object in the source file, and adding // the copy in the source file. Then the copied page dict object is // referenced and added to the destination file. // // This convoluted procedure is done because the copy is done by pdf_transplant // function that accepts a source and destination. Whatever is referenced by // destination object is deep copied // // allocate an object id and generation id in source file // // There is a bug in mupdf where the object allocation returns // 0 oid and 0 gid when the input pdf file has iref stream // so to work around the issue, we wrap the pdf_allocojbect // in a for loop 10 times to get the number // int sNum, sGen, tries; for (tries = 0; tries < 10; tries++) { error = pdf_allocobject(inFile->xref, &sNum, &sGen); if (error) return soPdfError(error); // If sNum is non zero then the allocation was successful if (sNum != 0) break; pdf_updateobject(inFile->xref, sNum, sGen, pageObj); } // If we didn't succeed even after 10 tries then this file // is not going to work. if (tries >= 10) return soPdfError(fz_throw("cannot allocate object because of mupdf bug")); // make a deep copy of the original page dict fz_obj *pageObj2; error = fz_deepcopydict(&pageObj2, pageObj); if (error) return soPdfError(error); // update the source file with the duplicate page object pdf_updateobject(inFile->xref, sNum, sGen, pageObj2); fz_dropobj(pageObj2); // create an indirect reference to the page object fz_obj *pageRef2; error = fz_newindirect(&pageRef2, sNum, sGen); if (error) return soPdfError(error); // delete the parent dictionary entry // Do we need to delete any other dictionary entry // like annot, tabs, metadata, etc fz_dictdels(pageObj2, "Parent"); // Set the media box setPageMediaBox(inFile->xref, pageObj2, bbRect[ctr]); // Set the rotation based on input switch(p_mode) { // no rotation if fit height case FitHeight: case Fit2xHeight: break; // rotate -90 deg if fit width case Fit2xWidth: case FitWidth: setPageRotate(pageObj2, p_reverseLandscape ? 90 : -90); break; case SmartFitHeight: case SmartFitWidth: default: return soPdfError(fz_throw("Mode(%d) not yet implemented.", p_mode)); break; } // push the indirect reference to the destination list for copy by pdf_transplant error = fz_arraypush(outFile->editobjs, pageRef2); if (error) return soPdfError(error); } } } // flush the objects into destination from source { fz_obj *results; int outPages; printf("\nCopying output page : "); error = pdf_transplant(outFile->xref, inFile->xref, &results, outFile->editobjs); if (error) return soPdfError(error); outPages = fz_arraylen(results); for (int ctr = 0; ctr < outPages; ctr++) { displayPageNumber(ctr + 1, !ctr); error = fz_arraypush(outFile->pagelist, fz_arrayget(results, p_reverseLandscape ? outPages - 1 - ctr : ctr)); if (error) return soPdfError(error); } fz_dropobj(results); } // flush page tree // Create page tree and add back-links { fz_obj *pageTreeObj; fz_obj *pageTreeRef; // allocate a new object in out file for pageTree object error = pdf_allocobject(outFile->xref, &pageTreeNum, &pageTreeGen); if (error) return soPdfError(error); // Create a page tree object error = fz_packobj(&pageTreeObj, "<</Type/Pages/Count %i/Kids %o>>", fz_arraylen(outFile->pagelist), outFile->pagelist); if (error) return soPdfError(error); // Update the xref entry with the pageTree object pdf_updateobject(outFile->xref, pageTreeNum, pageTreeGen, pageTreeObj); fz_dropobj(pageTreeObj); // Create a reference to the pageTree object error = fz_newindirect(&pageTreeRef, pageTreeNum, pageTreeGen); if (error) return soPdfError(error); // // For every page in the output file, update the parent entry // for (int ctr = 0; ctr < fz_arraylen(outFile->pagelist); ctr++) { fz_obj *pageObj; int num = fz_tonum(fz_arrayget(outFile->pagelist, ctr)); int gen = fz_togen(fz_arrayget(outFile->pagelist, ctr)); // Get the page object from xreft error = pdf_loadobject(&pageObj, outFile->xref, num, gen); if (error) return soPdfError(error); // Update the parent entry in the page dictionary error = fz_dictputs(pageObj, "Parent", pageTreeRef); if (error) return soPdfError(error); // Update the entry with the updated page object pdf_updateobject(outFile->xref, num, gen, pageObj); fz_dropobj(pageObj); } } // Create catalog and root entries { fz_obj *catObj, *infoObj; int rootNum, rootGen; int infoNum, infoGen; // // Copy the info catalog to the destination // alloc an object id and gen id in destination file error = pdf_allocobject(outFile->xref, &infoNum, &infoGen); if (error) return soPdfError(error); // make a deep copy of the original page dict error = fz_deepcopydict(&infoObj, inFile->xref->info); if (error) return soPdfError(error); // update the dest file with object pdf_updateobject(outFile->xref, infoNum, infoGen, infoObj); outFile->xref->info = infoObj; fz_dropobj(infoObj); // // root/catalog object creation error = pdf_allocobject(outFile->xref, &rootNum, &rootGen); if (error) return soPdfError(error); error = fz_packobj(&catObj, "<</Type/Catalog /Pages %r>>", pageTreeNum, pageTreeGen); if (error) return soPdfError(error); pdf_updateobject(outFile->xref, rootNum, rootGen, catObj); fz_dropobj(catObj); // Create trailer error = fz_packobj(&outFile->xref->trailer, "<</Root %r /Info %r>>", rootNum, rootGen, infoNum, infoGen); if (error) return soPdfError(error); } // Update the info in the target file and save the xref printf("\nSaving.\n"); error = setPageInfo(inFile, outFile); if (error) return soPdfError(error); error = pdf_savexref(outFile->xref, outFile->fileName, NULL); if (error) return soPdfError(error); if (g_errorCount != 0) { printf("\nFollowing issues encounted were ignored.\n\n"); for (int ctr = g_errorCount - 1; ctr >= 0; ctr--) soPdfError(g_errorList[ctr]); } printf("\nSaved.\n"); return 0; }
bool PdfBookReader::readBook(shared_ptr<ZLInputStream> stream) { if (stream.isNull() || !stream->open()) { return false; } readLine(*stream, myBuffer); if (!ZLStringUtil::stringStartsWith(myBuffer, "%PDF-")) { return false; } std::string version = myBuffer.substr(5); std::cerr << "version = " << version << "\n"; size_t eofOffset = stream->sizeOfOpened(); if (eofOffset < 100) { return false; } stream->seek(eofOffset - 100, true); bool readXrefOffset = false; size_t xrefOffset = (size_t)-1; while (true) { readLine(*stream, myBuffer); if (myBuffer.empty()) { break; } stripBuffer(myBuffer); if (readXrefOffset) { if (!myBuffer.empty()) { xrefOffset = atoi(myBuffer.c_str()); break; } } else if (myBuffer == "startxref") { readXrefOffset = true; } } if (!readReferenceTable(*stream, xrefOffset)) { return false; } PdfDictionaryObject &trailerDictionary = (PdfDictionaryObject&)*myTrailer; shared_ptr<PdfObject> root = resolveReference(trailerDictionary["Root"], *stream); if (root.isNull() || (root->type() != PdfObject::DICTIONARY)) { return false; } PdfDictionaryObject &rootDictionary = (PdfDictionaryObject&)*root; if (rootDictionary["Type"] != PdfNameObject::nameObject("Catalog")) { return false; } shared_ptr<PdfObject> pageRootNode = resolveReference(rootDictionary["Pages"], *stream); if (pageRootNode.isNull() || (pageRootNode->type() != PdfObject::DICTIONARY)) { return false; } PdfDictionaryObject &pageRootNodeDictionary = (PdfDictionaryObject&)*pageRootNode; if (pageRootNodeDictionary["Type"] != PdfNameObject::nameObject("Pages")) { return false; } /* shared_ptr<PdfObject> count = pageRootNodeDictionary["Count"]; if (!count.isNull() && (count->type() == PdfObject::INTEGER_NUMBER)) { std::cerr << "count = " << ((PdfIntegerObject&)*count).value() << "\n"; } */ shared_ptr<PdfObject> pages = pageRootNodeDictionary["Kids"]; if (pages.isNull() || (pages->type() != PdfObject::ARRAY)) { return false; } const PdfArrayObject& pagesArray = (const PdfArrayObject&)*pages; const size_t pageNumber = pagesArray.size(); for (size_t i = 0; i < pageNumber; ++i) { processPage(pagesArray[i], *stream); } return true; }
bool OggPacketiser::acceptOggPage(OggPage* inOggPage) { //AOP::: Needs closer look auto_ptr<OggPage> op(inOggPage); //All callers to acceptOggPage give away their pointer // to this function. All functions implementing this interface // are responsible for deleting this page. All callers // should NULL their pointer immediately after calling // to avoid reusing them. // //debugLog<<"acceptOggPage : Gran = "<<inOggPage->header()->GranulePos()<<"Num packs = "<<inOggPage->numPackets()<<endl; //If the page isn't a -1 page and it's got a different granpos save it. //if ( (inOggPage->header()->GranulePos() != -1) && (inOggPage->header()->GranulePos() != mCurrentGranPos)) { // mPrevGranPos = mCurrentGranPos; // //If the previous is higher than the // if (mPrevGranPos > mCurrentGranPos) { // mPrevGranPos = -1; // } // mCurrentGranPos = inOggPage->header()->GranulePos(); //} //If the page header says its a continuation page... if ((inOggPage->header()->HeaderFlags() & 1) == 1) { //debugLog<<"acceptOggPage : Page says cont..."<<endl; ///... and there is at least 1 packet... if (inOggPage->numPackets() > 0) { //debugLog<<"acceptOggPage : ...and there is at least 1 packet..."<<endl; //... and we were expecting a continuation... if (mPacketiserState == PKRSTATE_AWAITING_CONTINUATION) { //debugLog<<"acceptOggPage : ... and we were waiting for a cont..."<<endl; //... and the first packet is marked as a continuation... if (inOggPage->getStampedPacket(0)->isContinuation()) { //debugLog<<"acceptOggPage : ... and the first packet is a cont..."<<endl; //... merge this packet into our pending page. //ASSERT when mPacketiserState = PKRSTATE_AWAITING_CONTINUATION, mPending page != NULL mPendingPacket->merge(inOggPage->getStampedPacket(0)); //If even after merging this packet is still truncated... if (mPendingPacket->isTruncated()) { //debugLog<<"acceptOggPage : ... but the pending packet is still truncated..."<<endl; //Packet still not full. special case full page. //=== // The only way the the pending packet can be truncated is if // the first packet in the page is truncated, and the first // packet in a page can only be truncated if it's also the // only packet on the page. //Considering it is incomplete ending a page the granule pos // will be -1. //This is a special type of page : // 1 incomlpete packet on the page // Continuation flag set // No complete packets end on this page // Granule pos is -1 //debugLog<<"acceptOggPage : Go to cont state."<<endl; //We are still waiting for another continuation... mPacketiserState = PKRSTATE_AWAITING_CONTINUATION; //This should be redundant, we should already be in this state. //First packet on page is now merged into pending packet. } else { //debugLog<<"acceptOggPage : ... now we can deliver it..."<<endl; //... the pending packet is now complete. //TODO::: Static alternative here ? //Deliver the packet to the packet sink... if (dispatchStampedOggPacket(mPendingPacket) == false) { //debugLog<<"acceptOggPage : DELIVERY FAILED !"<<endl; mPacketiserState = PKRSTATE_OK; mPendingPacket = NULL; //delete inOggPage; //inOggPage = 0; return false; } //debugLog<<"acceptOggPage : ... delivery sucessful..."<<endl; //debugLog<<"acceptOggPage : Back to OK State..."<<endl; //Go back to OK state mPacketiserState = PKRSTATE_OK; mPendingPacket = NULL; //First packet on page is merged and delivered. } //debugLog<<"acceptOggPage : Send all the other packets besides first and last..."<<endl; //Send every packet except the first and last to the packet sink. processPage(inOggPage, false, false); } else { //debugLog<<"acceptOggPage : INTERNAL ERROR - Header says cont but packet doesn't."<<endl; //Header flag says continuation but first packet is not continued. mPacketiserState = PKRSTATE_INVALID_STREAM; //delete inOggPage; //inOggPage = 0; throw 0; } } else { //debugLog<<"acceptOggPage : UNEXPECTED CONT !"<<endl; if (mLooseMode == true) { //debugLog<<"acceptOggPage : ... but we are ignoring it !"<<endl; //Just ignore when we get continuation pages, just drop the broken bit of packet. if( mPendingPacket ) { delete mPendingPacket; mPendingPacket = NULL; } mPendingPacket = NULL; //MEMCHECK::: Did i just leak memory ? mPacketiserState = PKRSTATE_OK; //TODO::: Should really return false here if this returns false. if( processPage(inOggPage, false, false) == false) { //TODO::: State change ??? //delete inOggPage; //inOggPage = 0; return false; } } else { //debugLog<<"acceptOggPage : FAILURE !!!!"<<endl; //Unexpected continuation mPacketiserState = PKRSTATE_INVALID_STREAM; throw 0; } } } else { //debugLog<<"acceptOggPage : UNKNOWN CASE"<<endl; //Is this something ? //UNKNOWN CASE::: Header continuation flag set, but no packets on page. mPacketiserState = PKRSTATE_INVALID_STREAM; //delete inOggPage; //inOggPage = 0; throw 0; } } else { //debugLog<<"acceptOggPage : We have a normal page... dumping all but the last..."<<endl; //Normal page, no continuations... just dump the packets, except the last one if (inOggPage->numPackets() == 1) { //I think the bug is here... by sending a trunc packet and not updating state. //debugLog<<"acceptOggPage : Only one packet on this normal page..."<<endl; if (inOggPage->getPacket(0)->isTruncated()) { //debugLog<<"acceptOggPage : ...and it's truncated... so we save it."<<endl; //ASSERT : mPending packet is NULL, because this is not a continuation page. if( mPendingPacket ) { delete mPendingPacket; mPendingPacket = NULL; } mPendingPacket = (StampedOggPacket*)inOggPage->getStampedPacket(0)->clone(); //debugLog<<"acceptOggPage : Moving to CONT state."<<endl; mPacketiserState = PKRSTATE_AWAITING_CONTINUATION; } else { //debugLog<<"acceptOggPage : Only one packet on this normal page..."<<endl; if (processPage(inOggPage, true, true) == false ) { //If there was only one pack process it. //debugLog<<"acceptOggPage : FAIL STATE DELIVERY"<<endl; //TODO::: State change //delete inOggPage; //inOggPage = 0; return false; } //We should never go into the if below now as the packet is taken care of. } } else { //debugLog<<"acceptOggPage : More than one packet so dumping all but last..."<<endl; if (processPage(inOggPage, true, false) == false ) { //If there was only one packet, no packets would be written //debugLog<<"acceptOggPage : FAIL STATE DELIVERY"<<endl; //TODO::: State change //delete inOggPage; //inOggPage = 0; return false; } } //The first packet is delivered. } //debugLog<<"acceptOggPage : First pack should be delivered..."<<endl; //ASSERT: By this point something has been done with the first packet. // It was either merged with pending page and possibly delivered // or it was delivered by process page. //Code following assumes the first packet is dealt with already. //Now we deal with the last packet... //ASSERT : The last packet has only been sent if there was 1 or less packets. //If there is at least two packet on the page... ie at least one more packet we haven't processed. if (inOggPage->numPackets() > 1) { //debugLog<<"acceptOggPage : There is at least one packet on the page we haven't processed"<<endl; //... and we are in the OK state if (mPacketiserState == PKRSTATE_OK) { //debugLog<<"acceptOggPage : ... and we are in the OK state..."<<endl; //If the last packet is truncated. if (inOggPage->getPacket(inOggPage->numPackets() - 1)->isTruncated()) { //debugLog<<"acceptOggPage : ... but the last packet is trunced... so we save it and wait for cont..."<<endl; //The last packet is truncated. Save it and await continuation. //debugLog<<"acceptOggPage : Moving to CONT state..."<<endl; mPacketiserState = PKRSTATE_AWAITING_CONTINUATION; //ASSERT when mPacketiserState = OK, mPendingPacket = NULL if( mPendingPacket ) { delete mPendingPacket; mPendingPacket = NULL; } mPendingPacket = (StampedOggPacket*)(inOggPage->getStampedPacket(inOggPage->numPackets() - 1)->clone()); //This packet is not delivered, it waits for a continuation. } else { //We are in the OK state, with no pending packets, and the last packet is not truncated. //debugLog<<"acceptOggPage : The last page is not trunc so we send it..."<<endl; //Deliver to the packet sink. if ( dispatchStampedOggPacket( (StampedOggPacket*)(inOggPage->getStampedPacket(inOggPage->numPackets() - 1)->clone()) ) == false ) { //debugLog<<"acceptOggPage : Delivery failed..."<<endl; //TODO::: State change ? //delete inOggPage; //inOggPage = 0; return false; } //The last packet is complete. So send it. } } else if (mPacketiserState == PKRSTATE_AWAITING_CONTINUATION) { //FIX::: This case should never occur. //debugLog<<"acceptOggPage : NEVER BE HERE 1"<<endl; //Packetiser state is not ok... what to do abo8ut it. //See special page case above. //This can only happen when we went through the special case above, and kept // the state in the continuation state. But by definition it is impossible // for a subsequent packet on this page to be a continuation packet // as continuation packets can only be the first packet on the page. //This is more likely to be due to inconsistency of state code than invalidaity // of file. mPacketiserState = PKRSTATE_INVALID_STREAM; //delete inOggPage; //inOggPage = 0; throw 0; } else { //debugLog<<"acceptOggPage : NEVER BE HERE 2"<<endl; //Shouldn't be here mPacketiserState = PKRSTATE_INVALID_STREAM; //delete inOggPage; //inOggPage = 0; throw 0; } } else { //debugLog<<"acceptOggPage : 1 packet on page only, and we've taken care of it."<<endl; //Zero packets on page. } //debugLog<<"acceptOggPage : All ok... returning..."<<endl<<endl; //delete inOggPage; //inOggPage = 0; return true; }