diff options
Diffstat (limited to 'src')
32 files changed, 10581 insertions, 56 deletions
diff --git a/src/aig/aig/aigPartReg.c b/src/aig/aig/aigPartReg.c index 145d2029..96ad1812 100644 --- a/src/aig/aig/aigPartReg.c +++ b/src/aig/aig/aigPartReg.c @@ -482,8 +482,8 @@ Vec_Ptr_t * Aig_ManRegPartitionSimple( Aig_Man_t * pAig, int nPartSize, int nOve for ( Counter = 0; Counter < Aig_ManRegNum(pAig); Counter -= nOverSize ) { vPart = Vec_IntAlloc( nPartSize ); - for ( i = 0; i < nPartSize; i++ ) - if ( ++Counter < Aig_ManRegNum(pAig) ) + for ( i = 0; i < nPartSize; i++, Counter++ ) + if ( Counter < Aig_ManRegNum(pAig) ) Vec_IntPush( vPart, Counter ); if ( Vec_IntSize(vPart) <= nOverSize ) Vec_IntFree(vPart); diff --git a/src/aig/dar/darCut.c b/src/aig/dar/darCut.c index 79e4dcc4..6ebfec9d 100644 --- a/src/aig/dar/darCut.c +++ b/src/aig/dar/darCut.c @@ -586,7 +586,7 @@ Dar_Cut_t * Dar_ObjPrepareCuts( Dar_Man_t * p, Aig_Obj_t * pObj ) // create the cutset of the node pCutSet = (Dar_Cut_t *)Aig_MmFixedEntryFetch( p->pMemCuts ); Dar_ObjSetCuts( pObj, pCutSet ); - Dar_ObjForEachCut( pObj, pCut, i ) + Dar_ObjForEachCutAll( pObj, pCut, i ) pCut->fUsed = 0; // add unit cut if needed pCut = pCutSet; diff --git a/src/aig/fra/fra.h b/src/aig/fra/fra.h index 025ce046..e9e7ad9c 100644 --- a/src/aig/fra/fra.h +++ b/src/aig/fra/fra.h @@ -97,6 +97,7 @@ struct Fra_Ssw_t_ int nFramesK; // number of frames for induction (1=simple) int nMaxImps; // max implications to consider int nMaxLevs; // max levels to consider + int nMinDomSize; // min clock domain considered for optimization int fUseImps; // use implications int fRewrite; // enable rewriting of the specualatively reduced model int fFraiging; // enable comb SAT sweeping as preprocessing diff --git a/src/aig/fra/fraInd.c b/src/aig/fra/fraInd.c index 9c52d0e2..89c4c677 100644 --- a/src/aig/fra/fraInd.c +++ b/src/aig/fra/fraInd.c @@ -235,6 +235,43 @@ void Fra_FramesAddMore( Aig_Man_t * p, int nFrames ) /**Function************************************************************* + Synopsis [Divides a large partition into several ones.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Fra_FraigInductionPartDivide( Vec_Ptr_t * vResult, Vec_Int_t * vDomain, int nPartSize, int nOverSize ) +{ + Vec_Int_t * vPart; + int i, Counter; + assert( nPartSize && Vec_IntSize(vDomain) > nPartSize ); + if ( nOverSize >= nPartSize ) + { + printf( "Overlap size (%d) is more or equal than the partition size (%d).\n", nOverSize, nPartSize ); + printf( "Adjusting it to be equal to half of the partition size.\n" ); + nOverSize = nPartSize/2; + } + assert( nOverSize < nPartSize ); + for ( Counter = 0; Counter < Vec_IntSize(vDomain); Counter -= nOverSize ) + { + vPart = Vec_IntAlloc( nPartSize ); + for ( i = 0; i < nPartSize; i++, Counter++ ) + if ( Counter < Vec_IntSize(vDomain) ) + Vec_IntPush( vPart, Vec_IntEntry(vDomain, Counter) ); + if ( Vec_IntSize(vPart) <= nOverSize ) + Vec_IntFree(vPart); + else + Vec_PtrPush( vResult, vPart ); + } +} + + +/**Function************************************************************* + Synopsis [Performs partitioned sequential SAT sweepingG.] Description [] @@ -260,7 +297,20 @@ Aig_Man_t * Fra_FraigInductionPart( Aig_Man_t * pAig, Fra_Ssw_t * pPars ) nPartSize = pPars->nPartSize; pPars->nPartSize = 0; fVerbose = pPars->fVerbose; pPars->fVerbose = 0; // generate partitions - vResult = Aig_ManRegPartitionSimple( pAig, nPartSize, pPars->nOverSize ); + if ( pAig->vClockDoms ) + { + // divide large clock domains into separate partitions + vResult = Vec_PtrAlloc( 100 ); + Vec_PtrForEachEntry( (Vec_Ptr_t *)pAig->vClockDoms, vPart, i ) + { + if ( nPartSize && Vec_IntSize(vPart) > nPartSize ) + Fra_FraigInductionPartDivide( vResult, vPart, nPartSize, pPars->nOverSize ); + else + Vec_PtrPush( vResult, Vec_IntDup(vPart) ); + } + } + else + vResult = Aig_ManRegPartitionSimple( pAig, nPartSize, pPars->nOverSize ); // vResult = Aig_ManPartitionSmartRegisters( pAig, nPartSize, 0 ); // vResult = Aig_ManRegPartitionSmart( pAig, nPartSize ); if ( fPrintParts ) @@ -344,6 +394,8 @@ Aig_Man_t * Fra_FraigInduction( Aig_Man_t * pManAig, Fra_Ssw_t * pParams ) if ( Aig_ManNodeNum(pManAig) == 0 ) { pParams->nIters = 0; + // Ntl_ManFinalize() needs the following to satisfy an assertion + Aig_ManReprStart(pManAig,Aig_ManObjNumMax(pManAig)); return Aig_ManDupOrdered(pManAig); } assert( Aig_ManRegNum(pManAig) > 0 ); @@ -356,7 +408,8 @@ Aig_Man_t * Fra_FraigInduction( Aig_Man_t * pManAig, Fra_Ssw_t * pParams ) printf( "Partitioning was disabled to allow implication writing.\n" ); } // perform partitioning - if ( pParams->nPartSize > 0 && pParams->nPartSize < Aig_ManRegNum(pManAig) ) + if ( (pParams->nPartSize > 0 && pParams->nPartSize < Aig_ManRegNum(pManAig)) + || (pManAig->vClockDoms && Vec_VecSize(pManAig->vClockDoms) > 1) ) return Fra_FraigInductionPart( pManAig, pParams ); nNodesBeg = Aig_ManNodeNum(pManAig); diff --git a/src/aig/fra/fraLcr.c b/src/aig/fra/fraLcr.c index c957a751..92e0d94b 100644 --- a/src/aig/fra/fraLcr.c +++ b/src/aig/fra/fraLcr.c @@ -540,6 +540,8 @@ Aig_Man_t * Fra_FraigLatchCorrespondence( Aig_Man_t * pAig, int nFramesP, int nC if ( Aig_ManNodeNum(pAig) == 0 ) { if ( pnIter ) *pnIter = 0; + // Ntl_ManFinalize() requires the following to satisfy an assertion. + Aig_ManReprStart(pAig,Aig_ManObjNumMax(pAig)); return Aig_ManDupOrdered(pAig); } assert( Aig_ManRegNum(pAig) > 0 ); diff --git a/src/aig/ntl/ntl.h b/src/aig/ntl/ntl.h index 44a9f97c..e1d3edd1 100644 --- a/src/aig/ntl/ntl.h +++ b/src/aig/ntl/ntl.h @@ -95,10 +95,11 @@ struct Ntl_Mod_t_ Vec_Ptr_t * vPos; // the array of PO objects int nObjs[NTL_OBJ_VOID]; // counter of objects of each type // box attributes - unsigned int attrWhite : 1; // box has known logic - unsigned int attrBox : 1; // box is to remain unmapped - unsigned int attrComb : 1; // box is combinational - unsigned int attrKeep : 1; // box cannot be removed by structural sweep + unsigned int attrWhite :1; // box has known logic + unsigned int attrBox :1; // box is to remain unmapped + unsigned int attrComb :1; // box is combinational + unsigned int attrKeep :1; // box cannot be removed by structural sweep + unsigned int attrNoMerge :1; // box outputs cannot be merged // hashing names into nets Ntl_Net_t ** pTable; // the hash table of names into nets int nTableSize; // the allocated table size @@ -304,7 +305,7 @@ extern ABC_DLL Aig_Man_t * Ntl_ManPrepareSec( char * pFileName1, char * pFil extern ABC_DLL Aig_Man_t * Ntl_ManExtract( Ntl_Man_t * p ); extern ABC_DLL Aig_Man_t * Ntl_ManCollapse( Ntl_Man_t * p, int fSeq ); extern ABC_DLL Aig_Man_t * Ntl_ManCollapseComb( Ntl_Man_t * p ); -extern ABC_DLL Aig_Man_t * Ntl_ManCollapseSeq( Ntl_Man_t * p ); +extern ABC_DLL Aig_Man_t * Ntl_ManCollapseSeq( Ntl_Man_t * p, int nMinDomSize ); /*=== ntlInsert.c ==========================================================*/ extern ABC_DLL Ntl_Man_t * Ntl_ManInsertMapping( Ntl_Man_t * p, Vec_Ptr_t * vMapping, Aig_Man_t * pAig ); extern ABC_DLL Ntl_Man_t * Ntl_ManInsertAig( Ntl_Man_t * p, Aig_Man_t * pAig ); diff --git a/src/aig/ntl/ntlExtract.c b/src/aig/ntl/ntlExtract.c index d6cbfab0..8049ffb8 100644 --- a/src/aig/ntl/ntlExtract.c +++ b/src/aig/ntl/ntlExtract.c @@ -621,7 +621,7 @@ Aig_Man_t * Ntl_ManCollapseComb( Ntl_Man_t * p ) SeeAlso [] ***********************************************************************/ -Aig_Man_t * Ntl_ManCollapseSeq( Ntl_Man_t * p ) +Aig_Man_t * Ntl_ManCollapseSeq( Ntl_Man_t * p, int nMinDomSize ) { Aig_Man_t * pAig; Ntl_Mod_t * pRoot; @@ -643,13 +643,14 @@ Aig_Man_t * Ntl_ManCollapseSeq( Ntl_Man_t * p ) // perform the traversal pAig = Ntl_ManCollapse( p, 1 ); // check if there are register classes - pAig->vClockDoms = Ntl_ManTransformRegClasses( p, 100, 1 ); + pAig->vClockDoms = Ntl_ManTransformRegClasses( p, nMinDomSize, 1 ); if ( pAig->vClockDoms ) { if ( Vec_VecSize(pAig->vClockDoms) == 0 ) printf( "Clock domains are small. Seq synthesis is not performed.\n" ); else printf( "Performing seq synthesis for %d clock domains.\n", Vec_VecSize(pAig->vClockDoms) ); + printf( "\n" ); } return pAig; } diff --git a/src/aig/ntl/ntlFraig.c b/src/aig/ntl/ntlFraig.c index 6dce3645..6449cc33 100644 --- a/src/aig/ntl/ntlFraig.c +++ b/src/aig/ntl/ntlFraig.c @@ -148,6 +148,9 @@ void Ntl_ManReduce( Ntl_Man_t * p, Aig_Man_t * pAig ) // do not reduce the net if it is driven by a multi-output box if ( Ntl_ObjIsBox(pNet->pDriver) && Ntl_ObjFanoutNum(pNet->pDriver) > 1 ) continue; + // do not reduce the net if it has no-merge attribute + if ( Ntl_ObjIsBox(pNet->pDriver) && pNet->pDriver->pImplem->attrNoMerge ) + continue; pNetRepr = pObjRepr->pData; if ( pNetRepr == NULL ) { @@ -311,7 +314,7 @@ Ntl_Man_t * Ntl_ManScl( Ntl_Man_t * p, int fLatchConst, int fLatchEqual, int fVe // collapse the AIG pAig = Ntl_ManExtract( p ); pNew = Ntl_ManInsertAig( p, pAig ); - pAigCol = Ntl_ManCollapseSeq( pNew ); + pAigCol = Ntl_ManCollapseSeq( pNew, 0 ); //Saig_ManDumpBlif( pAigCol, "1s.blif" ); // perform SCL for the given design @@ -345,7 +348,7 @@ Ntl_Man_t * Ntl_ManLcorr( Ntl_Man_t * p, int nConfMax, int fVerbose ) // collapse the AIG pAig = Ntl_ManExtract( p ); pNew = Ntl_ManInsertAig( p, pAig ); - pAigCol = Ntl_ManCollapseSeq( pNew ); + pAigCol = Ntl_ManCollapseSeq( pNew, 0 ); // perform SCL for the given design pTemp = Fra_FraigLatchCorrespondence( pAigCol, 0, nConfMax, 0, fVerbose, NULL, 0 ); @@ -378,7 +381,7 @@ Ntl_Man_t * Ntl_ManSsw( Ntl_Man_t * p, Fra_Ssw_t * pPars ) // collapse the AIG pAig = Ntl_ManExtract( p ); pNew = Ntl_ManInsertAig( p, pAig ); - pAigCol = Ntl_ManCollapseSeq( pNew ); + pAigCol = Ntl_ManCollapseSeq( pNew, pPars->nMinDomSize ); // perform SCL for the given design pTemp = Fra_FraigInduction( pAigCol, pPars ); @@ -554,7 +557,7 @@ Ntl_Man_t * Ntl_ManSsw2( Ntl_Man_t * p, Fra_Ssw_t * pPars ) Ntl_Man_t * pNew; Aig_Man_t * pAigRed, * pAigCol; // collapse the AIG - pAigCol = Ntl_ManCollapseSeq( p ); + pAigCol = Ntl_ManCollapseSeq( p, pPars->nMinDomSize ); // transform the collapsed AIG pAigRed = Fra_FraigInduction( pAigCol, pPars ); Aig_ManStop( pAigRed ); diff --git a/src/aig/ntl/ntlMan.c b/src/aig/ntl/ntlMan.c index cee0bf6c..06a1a51c 100644 --- a/src/aig/ntl/ntlMan.c +++ b/src/aig/ntl/ntlMan.c @@ -324,10 +324,11 @@ Ntl_Mod_t * Ntl_ModelAlloc( Ntl_Man_t * pMan, char * pName ) // start the manager p = ALLOC( Ntl_Mod_t, 1 ); memset( p, 0, sizeof(Ntl_Mod_t) ); - p->attrBox = 1; - p->attrComb = 1; - p->attrWhite = 1; - p->attrKeep = 0; + p->attrBox = 1; + p->attrComb = 1; + p->attrWhite = 1; + p->attrKeep = 0; + p->attrNoMerge = 0; p->pMan = pMan; p->pName = Ntl_ManStoreName( p->pMan, pName ); p->vObjs = Vec_PtrAlloc( 100 ); diff --git a/src/aig/ntl/ntlReadBlif.c b/src/aig/ntl/ntlReadBlif.c index ebfb2a80..cc019732 100644 --- a/src/aig/ntl/ntlReadBlif.c +++ b/src/aig/ntl/ntlReadBlif.c @@ -19,6 +19,7 @@ ***********************************************************************/ #include "ntl.h" +#include <bzlib.h> //////////////////////////////////////////////////////////////////////// /// DECLARATIONS /// @@ -41,6 +42,11 @@ struct Ioa_ReadMod_t_ Vec_Ptr_t * vTimeInputs; // .input_arrival/required lines Vec_Ptr_t * vTimeOutputs; // .output_required/arrival lines int fBlackBox; // indicates blackbox model + int fNoMerge; // indicates no-merge model + char fInArr; + char fInReq; + char fOutArr; + char fOutReq; // the resulting network Ntl_Mod_t * pNtk; // the parent manager @@ -75,6 +81,7 @@ static void Ioa_ReadFree( Ioa_ReadMan_t * p ); static Ioa_ReadMod_t * Ioa_ReadModAlloc(); static void Ioa_ReadModFree( Ioa_ReadMod_t * p ); static char * Ioa_ReadLoadFile( char * pFileName ); +static char * Ioa_ReadLoadFileBz2( char * pFileName ); static void Ioa_ReadReadPreparse( Ioa_ReadMan_t * p ); static int Ioa_ReadReadInterfaces( Ioa_ReadMan_t * p ); static Ntl_Man_t * Ioa_ReadParse( Ioa_ReadMan_t * p ); @@ -91,6 +98,7 @@ static int Ioa_ReadParseLineNamesBlif( Ioa_ReadMod_t * p, char * p static int Ioa_ReadCharIsSpace( char s ) { return s == ' ' || s == '\t' || s == '\r' || s == '\n'; } static int Ioa_ReadCharIsSopSymb( char s ) { return s == '0' || s == '1' || s == '-' || s == '\r' || s == '\n'; } + //////////////////////////////////////////////////////////////////////// /// FUNCTION DEFINITIONS /// //////////////////////////////////////////////////////////////////////// @@ -125,7 +133,10 @@ Ntl_Man_t * Ioa_ReadBlif( char * pFileName, int fCheck ) // start the file reader p = Ioa_ReadAlloc(); p->pFileName = pFileName; - p->pBuffer = Ioa_ReadLoadFile( pFileName ); + if ( !strncmp(pFileName+strlen(pFileName)-4,".bz2",4) ) + p->pBuffer = Ioa_ReadLoadFileBz2( pFileName ); + else + p->pBuffer = Ioa_ReadLoadFile( pFileName ); if ( p->pBuffer == NULL ) { Ioa_ReadFree( p ); @@ -173,6 +184,12 @@ Ntl_Man_t * Ioa_ReadBlif( char * pFileName, int fCheck ) // if ( (nNodes = Ntl_ManReconnectCoDrivers(pDesign)) ) // printf( "The design was transformed by removing %d buf/inv CO drivers.\n", nNodes ); //Ioa_WriteBlif( pDesign, "_temp_.blif" ); +/* + { + Aig_Man_t * p = Ntl_ManCollapseSeq( pDesign ); + Aig_ManStop( p ); + } +*/ return pDesign; } @@ -437,6 +454,91 @@ static char * Ioa_ReadLoadFile( char * pFileName ) /**Function************************************************************* + Synopsis [Reads the file into a character buffer.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +typedef struct buflist { + char buf[1<<20]; + int nBuf; + struct buflist * next; +} buflist; + +static char * Ioa_ReadLoadFileBz2( char * pFileName ) +{ + FILE * pFile; + int nFileSize = 0; + char * pContents; + BZFILE * b; + int bzError; + struct buflist * pNext; + buflist * bufHead = NULL, * buf = NULL; + + pFile = fopen( pFileName, "rb" ); + if ( pFile == NULL ) + { + printf( "Ioa_ReadLoadFileBz2(): The file is unavailable (absent or open).\n" ); + return NULL; + } + b = BZ2_bzReadOpen(&bzError,pFile,0,0,NULL,0); + if (bzError != BZ_OK) { + printf( "Ioa_ReadLoadFileBz2(): BZ2_bzReadOpen() failed with error %d.\n",bzError ); + return NULL; + } + do { + if (!bufHead) + buf = bufHead = ALLOC( buflist, 1 ); + else + buf = buf->next = ALLOC( buflist, 1 ); + nFileSize += buf->nBuf = BZ2_bzRead(&bzError,b,buf->buf,1<<20); + buf->next = NULL; + } while (bzError == BZ_OK); + if (bzError == BZ_STREAM_END) { + // we're okay + char * p; + int nBytes = 0; + BZ2_bzReadClose(&bzError,b); + p = pContents = ALLOC( char, nFileSize + 10 ); + buf = bufHead; + do { + memcpy(p+nBytes,buf->buf,buf->nBuf); + nBytes += buf->nBuf; +// } while((buf = buf->next)); + pNext = buf->next; + free( buf ); + } while((buf = pNext)); + } else if (bzError == BZ_DATA_ERROR_MAGIC) { + // not a BZIP2 file + BZ2_bzReadClose(&bzError,b); + fseek( pFile, 0, SEEK_END ); + nFileSize = ftell( pFile ); + if ( nFileSize == 0 ) + { + printf( "Ioa_ReadLoadFileBz2(): The file is empty.\n" ); + return NULL; + } + pContents = ALLOC( char, nFileSize + 10 ); + rewind( pFile ); + fread( pContents, nFileSize, 1, pFile ); + } else { + // Some other error. + printf( "Ioa_ReadLoadFileBz2(): Unable to read the compressed BLIF.\n" ); + return NULL; + } + fclose( pFile ); + // finish off the file with the spare .end line + // some benchmarks suddenly break off without this line + strcpy( pContents + nFileSize, "\n.end\n" ); + return pContents; +} + +/**Function************************************************************* + Synopsis [Prepares the parsing.] Description [Performs several preliminary operations: @@ -485,7 +587,7 @@ static void Ioa_ReadReadPreparse( Ioa_ReadMan_t * p ) if ( !Ioa_ReadCharIsSpace(*pPrev) ) break; // if it is the line extender, overwrite it with spaces - if ( *pPrev == '\\' ) + if ( pPrev >= p->pBuffer && *pPrev == '\\' ) { for ( ; *pPrev; pPrev++ ) *pPrev = ' '; @@ -511,10 +613,22 @@ static void Ioa_ReadReadPreparse( Ioa_ReadMan_t * p ) Vec_PtrPush( p->pLatest->vDelays, pCur ); else if ( !strncmp(pCur, "input_arrival", 13) || !strncmp(pCur, "input_required", 14) ) + { + if ( !strncmp(pCur, "input_arrival", 13) ) + p->pLatest->fInArr = 1; + if ( !strncmp(pCur, "input_required", 14) ) + p->pLatest->fInReq = 1; Vec_PtrPush( p->pLatest->vTimeInputs, pCur ); - else if ( !strncmp(pCur, "output_required", 14) || - !strncmp(pCur, "output_arrival", 13) ) + } + else if ( !strncmp(pCur, "output_required", 15) || + !strncmp(pCur, "output_arrival", 14) ) + { + if ( !strncmp(pCur, "output_required", 15) ) + p->pLatest->fOutReq = 1; + if ( !strncmp(pCur, "output_arrival", 14) ) + p->pLatest->fOutArr = 1; Vec_PtrPush( p->pLatest->vTimeOutputs, pCur ); + } else if ( !strncmp(pCur, "blackbox", 8) ) p->pLatest->fBlackBox = 1; else if ( !strncmp(pCur, "model", 5) ) @@ -543,6 +657,7 @@ static void Ioa_ReadReadPreparse( Ioa_ReadMan_t * p ) } else if ( !strncmp(pCur, "no_merge", 8) ) { + p->pLatest->fNoMerge = 1; } else { @@ -579,6 +694,9 @@ static int Ioa_ReadReadInterfaces( Ioa_ReadMan_t * p ) // parse the model attributes if ( pMod->pAttrib && !Ioa_ReadParseLineAttrib( pMod, pMod->pAttrib ) ) return 0; + // parse no-merge + if ( pMod->fNoMerge ) + pMod->pNtk->attrNoMerge = 1; // parse the inputs Vec_PtrForEachEntry( pMod->vInputs, pLine, k ) if ( !Ioa_ReadParseLineInputs( pMod, pLine ) ) @@ -597,6 +715,15 @@ static int Ioa_ReadReadInterfaces( Ioa_ReadMan_t * p ) Vec_PtrForEachEntry( pMod->vTimeOutputs, pLine, k ) if ( !Ioa_ReadParseLineTimes( pMod, pLine, 1 ) ) return 0; + // report timing line stats + if ( pMod->fInArr && pMod->fInReq ) + printf( "Model %s has both .input_arrival and .input_required.\n", pMod->pNtk->pName ); + if ( pMod->fOutArr && pMod->fOutReq ) + printf( "Model %s has both .output_arrival and .output_required.\n", pMod->pNtk->pName ); + if ( !pMod->vDelays && !pMod->fInArr && !pMod->fInReq ) + printf( "Model %s has neither .input_arrival nor .input_required.\n", pMod->pNtk->pName ); + if ( !pMod->vDelays && !pMod->fOutArr && !pMod->fOutReq ) + printf( "Model %s has neither .output_arrival nor .output_required.\n", pMod->pNtk->pName ); } return 1; } diff --git a/src/aig/ntl/ntlReadBlif_old.c b/src/aig/ntl/ntlReadBlif_old.c new file mode 100644 index 00000000..ebfb2a80 --- /dev/null +++ b/src/aig/ntl/ntlReadBlif_old.c @@ -0,0 +1,1261 @@ +/**CFile**************************************************************** + + FileName [ntlReadBlif.c] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [Command processing package.] + + Synopsis [Procedures to read BLIF file.] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - January 8, 2007.] + + Revision [$Id: ntlReadBlif.c,v 1.00 2007/01/08 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#include "ntl.h" + +//////////////////////////////////////////////////////////////////////// +/// DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +typedef struct Ioa_ReadMod_t_ Ioa_ReadMod_t; // parsing model +typedef struct Ioa_ReadMan_t_ Ioa_ReadMan_t; // parsing manager + +struct Ioa_ReadMod_t_ +{ + // file lines + char * pFirst; // .model line + char * pAttrib; // .attrib line + Vec_Ptr_t * vInputs; // .inputs lines + Vec_Ptr_t * vOutputs; // .outputs lines + Vec_Ptr_t * vLatches; // .latch lines + Vec_Ptr_t * vNames; // .names lines + Vec_Ptr_t * vSubckts; // .subckt lines + Vec_Ptr_t * vDelays; // .delay lines + Vec_Ptr_t * vTimeInputs; // .input_arrival/required lines + Vec_Ptr_t * vTimeOutputs; // .output_required/arrival lines + int fBlackBox; // indicates blackbox model + // the resulting network + Ntl_Mod_t * pNtk; + // the parent manager + Ioa_ReadMan_t * pMan; +}; + +struct Ioa_ReadMan_t_ +{ + // general info about file + char * pFileName; // the name of the file + char * pBuffer; // the contents of the file + Vec_Ptr_t * vLines; // the line beginnings + // the results of reading + Ntl_Man_t * pDesign; // the design under construction + // intermediate storage for models + Vec_Ptr_t * vModels; // vector of models + Ioa_ReadMod_t * pLatest; // the current model + // current processing info + Vec_Ptr_t * vTokens; // the current tokens + Vec_Ptr_t * vTokens2; // the current tokens + Vec_Str_t * vFunc; // the local function + // error reporting + char sError[512]; // the error string generated during parsing + // statistics + int nTablesRead; // the number of processed tables + int nTablesLeft; // the number of dangling tables +}; + +// static functions +static Ioa_ReadMan_t * Ioa_ReadAlloc(); +static void Ioa_ReadFree( Ioa_ReadMan_t * p ); +static Ioa_ReadMod_t * Ioa_ReadModAlloc(); +static void Ioa_ReadModFree( Ioa_ReadMod_t * p ); +static char * Ioa_ReadLoadFile( char * pFileName ); +static void Ioa_ReadReadPreparse( Ioa_ReadMan_t * p ); +static int Ioa_ReadReadInterfaces( Ioa_ReadMan_t * p ); +static Ntl_Man_t * Ioa_ReadParse( Ioa_ReadMan_t * p ); +static int Ioa_ReadParseLineModel( Ioa_ReadMod_t * p, char * pLine ); +static int Ioa_ReadParseLineAttrib( Ioa_ReadMod_t * p, char * pLine ); +static int Ioa_ReadParseLineInputs( Ioa_ReadMod_t * p, char * pLine ); +static int Ioa_ReadParseLineOutputs( Ioa_ReadMod_t * p, char * pLine ); +static int Ioa_ReadParseLineLatch( Ioa_ReadMod_t * p, char * pLine ); +static int Ioa_ReadParseLineSubckt( Ioa_ReadMod_t * p, char * pLine ); +static int Ioa_ReadParseLineDelay( Ioa_ReadMod_t * p, char * pLine ); +static int Ioa_ReadParseLineTimes( Ioa_ReadMod_t * p, char * pLine, int fOutput ); +static int Ioa_ReadParseLineNamesBlif( Ioa_ReadMod_t * p, char * pLine ); + +static int Ioa_ReadCharIsSpace( char s ) { return s == ' ' || s == '\t' || s == '\r' || s == '\n'; } +static int Ioa_ReadCharIsSopSymb( char s ) { return s == '0' || s == '1' || s == '-' || s == '\r' || s == '\n'; } + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +/**Function************************************************************* + + Synopsis [Reads the network from the BLIF file.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Ntl_Man_t * Ioa_ReadBlif( char * pFileName, int fCheck ) +{ + FILE * pFile; + Ioa_ReadMan_t * p; + Ntl_Man_t * pDesign; +// int nNodes; + + // check that the file is available + pFile = fopen( pFileName, "rb" ); + if ( pFile == NULL ) + { + printf( "Ioa_ReadBlif(): The file is unavailable (absent or open).\n" ); + return 0; + } + fclose( pFile ); + + // start the file reader + p = Ioa_ReadAlloc(); + p->pFileName = pFileName; + p->pBuffer = Ioa_ReadLoadFile( pFileName ); + if ( p->pBuffer == NULL ) + { + Ioa_ReadFree( p ); + return NULL; + } + // set the design name + p->pDesign = Ntl_ManAlloc( pFileName ); + p->pDesign->pName = Ntl_ManStoreFileName( p->pDesign, pFileName ); + p->pDesign->pSpec = Ntl_ManStoreName( p->pDesign, pFileName ); + // prepare the file for parsing + Ioa_ReadReadPreparse( p ); + // parse interfaces of each network + if ( !Ioa_ReadReadInterfaces( p ) ) + { + if ( p->sError[0] ) + fprintf( stdout, "%s\n", p->sError ); + Ioa_ReadFree( p ); + return NULL; + } + // construct the network + pDesign = Ioa_ReadParse( p ); + if ( p->sError[0] ) + fprintf( stdout, "%s\n", p->sError ); + if ( pDesign == NULL ) + { + Ioa_ReadFree( p ); + return NULL; + } + p->pDesign = NULL; + Ioa_ReadFree( p ); +// pDesign should be linked to all models of the design + + // make sure that everything is okay with the network structure + if ( fCheck ) + { + if ( !Ntl_ManCheck( pDesign ) ) + { + printf( "Ioa_ReadBlif: The check has failed for design %s.\n", pDesign->pName ); + Ntl_ManFree( pDesign ); + return NULL; + } + + } + // transform the design by removing the CO drivers +// if ( (nNodes = Ntl_ManReconnectCoDrivers(pDesign)) ) +// printf( "The design was transformed by removing %d buf/inv CO drivers.\n", nNodes ); +//Ioa_WriteBlif( pDesign, "_temp_.blif" ); + return pDesign; +} + +/**Function************************************************************* + + Synopsis [Allocates the BLIF parsing structure.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static Ioa_ReadMan_t * Ioa_ReadAlloc() +{ + Ioa_ReadMan_t * p; + p = ALLOC( Ioa_ReadMan_t, 1 ); + memset( p, 0, sizeof(Ioa_ReadMan_t) ); + p->vLines = Vec_PtrAlloc( 512 ); + p->vModels = Vec_PtrAlloc( 512 ); + p->vTokens = Vec_PtrAlloc( 512 ); + p->vTokens2 = Vec_PtrAlloc( 512 ); + p->vFunc = Vec_StrAlloc( 512 ); + return p; +} + +/**Function************************************************************* + + Synopsis [Frees the BLIF parsing structure.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static void Ioa_ReadFree( Ioa_ReadMan_t * p ) +{ + Ioa_ReadMod_t * pMod; + int i; + if ( p->pDesign ) + Ntl_ManFree( p->pDesign ); + if ( p->pBuffer ) + free( p->pBuffer ); + if ( p->vLines ) + Vec_PtrFree( p->vLines ); + if ( p->vModels ) + { + Vec_PtrForEachEntry( p->vModels, pMod, i ) + Ioa_ReadModFree( pMod ); + Vec_PtrFree( p->vModels ); + } + Vec_PtrFree( p->vTokens ); + Vec_PtrFree( p->vTokens2 ); + Vec_StrFree( p->vFunc ); + free( p ); +} + +/**Function************************************************************* + + Synopsis [Allocates the BLIF parsing structure for one model.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static Ioa_ReadMod_t * Ioa_ReadModAlloc() +{ + Ioa_ReadMod_t * p; + p = ALLOC( Ioa_ReadMod_t, 1 ); + memset( p, 0, sizeof(Ioa_ReadMod_t) ); + p->vInputs = Vec_PtrAlloc( 8 ); + p->vOutputs = Vec_PtrAlloc( 8 ); + p->vLatches = Vec_PtrAlloc( 8 ); + p->vNames = Vec_PtrAlloc( 8 ); + p->vSubckts = Vec_PtrAlloc( 8 ); + p->vDelays = Vec_PtrAlloc( 8 ); + p->vTimeInputs = Vec_PtrAlloc( 8 ); + p->vTimeOutputs = Vec_PtrAlloc( 8 ); + return p; +} + +/**Function************************************************************* + + Synopsis [Deallocates the BLIF parsing structure for one model.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static void Ioa_ReadModFree( Ioa_ReadMod_t * p ) +{ + Vec_PtrFree( p->vInputs ); + Vec_PtrFree( p->vOutputs ); + Vec_PtrFree( p->vLatches ); + Vec_PtrFree( p->vNames ); + Vec_PtrFree( p->vSubckts ); + Vec_PtrFree( p->vDelays ); + Vec_PtrFree( p->vTimeInputs ); + Vec_PtrFree( p->vTimeOutputs ); + free( p ); +} + + + +/**Function************************************************************* + + Synopsis [Counts the number of given chars.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static int Ioa_ReadCountChars( char * pLine, char Char ) +{ + char * pCur; + int Counter = 0; + for ( pCur = pLine; *pCur; pCur++ ) + if ( *pCur == Char ) + Counter++; + return Counter; +} + +/**Function************************************************************* + + Synopsis [Collects the already split tokens.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static void Ioa_ReadCollectTokens( Vec_Ptr_t * vTokens, char * pInput, char * pOutput ) +{ + char * pCur; + Vec_PtrClear( vTokens ); + for ( pCur = pInput; pCur < pOutput; pCur++ ) + { + if ( *pCur == 0 ) + continue; + Vec_PtrPush( vTokens, pCur ); + while ( *++pCur ); + } +} + +/**Function************************************************************* + + Synopsis [Splits the line into tokens.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static void Ioa_ReadSplitIntoTokens( Vec_Ptr_t * vTokens, char * pLine, char Stop ) +{ + char * pCur; + // clear spaces + for ( pCur = pLine; *pCur != Stop; pCur++ ) + if ( Ioa_ReadCharIsSpace(*pCur) ) + *pCur = 0; + // collect tokens + Ioa_ReadCollectTokens( vTokens, pLine, pCur ); +} + +/**Function************************************************************* + + Synopsis [Splits the line into tokens.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static void Ioa_ReadSplitIntoTokensAndClear( Vec_Ptr_t * vTokens, char * pLine, char Stop, char Char ) +{ + char * pCur; + // clear spaces + for ( pCur = pLine; *pCur != Stop; pCur++ ) + if ( Ioa_ReadCharIsSpace(*pCur) || *pCur == Char ) + *pCur = 0; + // collect tokens + Ioa_ReadCollectTokens( vTokens, pLine, pCur ); +} + +/**Function************************************************************* + + Synopsis [Returns the 1-based number of the line in which the token occurs.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static int Ioa_ReadGetLine( Ioa_ReadMan_t * p, char * pToken ) +{ + char * pLine; + int i; + Vec_PtrForEachEntry( p->vLines, pLine, i ) + if ( pToken < pLine ) + return i; + return -1; +} + +/**Function************************************************************* + + Synopsis [Reads the file into a character buffer.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static char * Ioa_ReadLoadFile( char * pFileName ) +{ + FILE * pFile; + int nFileSize; + char * pContents; + pFile = fopen( pFileName, "rb" ); + if ( pFile == NULL ) + { + printf( "Ioa_ReadLoadFile(): The file is unavailable (absent or open).\n" ); + return NULL; + } + fseek( pFile, 0, SEEK_END ); + nFileSize = ftell( pFile ); + if ( nFileSize == 0 ) + { + printf( "Ioa_ReadLoadFile(): The file is empty.\n" ); + return NULL; + } + pContents = ALLOC( char, nFileSize + 10 ); + rewind( pFile ); + fread( pContents, nFileSize, 1, pFile ); + fclose( pFile ); + // finish off the file with the spare .end line + // some benchmarks suddenly break off without this line + strcpy( pContents + nFileSize, "\n.end\n" ); + return pContents; +} + +/**Function************************************************************* + + Synopsis [Prepares the parsing.] + + Description [Performs several preliminary operations: + - Cuts the file buffer into separate lines. + - Removes comments and line extenders. + - Sorts lines by directives. + - Estimates the number of objects. + - Allocates room for the objects. + - Allocates room for the hash table.] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static void Ioa_ReadReadPreparse( Ioa_ReadMan_t * p ) +{ + char * pCur, * pPrev; + int i, fComment = 0; + // parse the buffer into lines and remove comments + Vec_PtrPush( p->vLines, p->pBuffer ); + for ( pCur = p->pBuffer; *pCur; pCur++ ) + { + if ( *pCur == '\n' ) + { + *pCur = 0; +// if ( *(pCur-1) == '\r' ) +// *(pCur-1) = 0; + fComment = 0; + Vec_PtrPush( p->vLines, pCur + 1 ); + } + else if ( *pCur == '#' ) + fComment = 1; + // remove comments + if ( fComment ) + *pCur = 0; + } + + // unfold the line extensions and sort lines by directive + Vec_PtrForEachEntry( p->vLines, pCur, i ) + { + if ( *pCur == 0 ) + continue; + // find previous non-space character + for ( pPrev = pCur - 2; pPrev >= p->pBuffer; pPrev-- ) + if ( !Ioa_ReadCharIsSpace(*pPrev) ) + break; + // if it is the line extender, overwrite it with spaces + if ( *pPrev == '\\' ) + { + for ( ; *pPrev; pPrev++ ) + *pPrev = ' '; + *pPrev = ' '; + continue; + } + // skip spaces at the beginning of the line + while ( Ioa_ReadCharIsSpace(*pCur++) ); + // parse directives + if ( *(pCur-1) != '.' ) + continue; + if ( !strncmp(pCur, "names", 5) ) + Vec_PtrPush( p->pLatest->vNames, pCur ); + else if ( !strncmp(pCur, "latch", 5) ) + Vec_PtrPush( p->pLatest->vLatches, pCur ); + else if ( !strncmp(pCur, "inputs", 6) ) + Vec_PtrPush( p->pLatest->vInputs, pCur ); + else if ( !strncmp(pCur, "outputs", 7) ) + Vec_PtrPush( p->pLatest->vOutputs, pCur ); + else if ( !strncmp(pCur, "subckt", 6) ) + Vec_PtrPush( p->pLatest->vSubckts, pCur ); + else if ( !strncmp(pCur, "delay", 5) ) + Vec_PtrPush( p->pLatest->vDelays, pCur ); + else if ( !strncmp(pCur, "input_arrival", 13) || + !strncmp(pCur, "input_required", 14) ) + Vec_PtrPush( p->pLatest->vTimeInputs, pCur ); + else if ( !strncmp(pCur, "output_required", 14) || + !strncmp(pCur, "output_arrival", 13) ) + Vec_PtrPush( p->pLatest->vTimeOutputs, pCur ); + else if ( !strncmp(pCur, "blackbox", 8) ) + p->pLatest->fBlackBox = 1; + else if ( !strncmp(pCur, "model", 5) ) + { + p->pLatest = Ioa_ReadModAlloc(); + p->pLatest->pFirst = pCur; + p->pLatest->pMan = p; + } + else if ( !strncmp(pCur, "attrib", 6) ) + { + if ( p->pLatest->pAttrib != NULL ) + fprintf( stdout, "Line %d: Skipping second .attrib line for this model.\n", Ioa_ReadGetLine(p, pCur) ); + else + p->pLatest->pAttrib = pCur; + } + else if ( !strncmp(pCur, "end", 3) ) + { + if ( p->pLatest ) + Vec_PtrPush( p->vModels, p->pLatest ); + p->pLatest = NULL; + } + else if ( !strncmp(pCur, "exdc", 4) ) + { + fprintf( stdout, "Line %d: Skipping EXDC network.\n", Ioa_ReadGetLine(p, pCur) ); + break; + } + else if ( !strncmp(pCur, "no_merge", 8) ) + { + } + else + { + pCur--; + if ( pCur[strlen(pCur)-1] == '\r' ) + pCur[strlen(pCur)-1] = 0; + fprintf( stdout, "Line %d: Skipping line \"%s\".\n", Ioa_ReadGetLine(p, pCur), pCur ); + } + } +} + +/**Function************************************************************* + + Synopsis [Parses interfaces of the models.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static int Ioa_ReadReadInterfaces( Ioa_ReadMan_t * p ) +{ + Ioa_ReadMod_t * pMod; + char * pLine; + int i, k; + // iterate through the models + Vec_PtrForEachEntry( p->vModels, pMod, i ) + { + // parse the model + if ( !Ioa_ReadParseLineModel( pMod, pMod->pFirst ) ) + return 0; + // parse the model attributes + if ( pMod->pAttrib && !Ioa_ReadParseLineAttrib( pMod, pMod->pAttrib ) ) + return 0; + // parse the inputs + Vec_PtrForEachEntry( pMod->vInputs, pLine, k ) + if ( !Ioa_ReadParseLineInputs( pMod, pLine ) ) + return 0; + // parse the outputs + Vec_PtrForEachEntry( pMod->vOutputs, pLine, k ) + if ( !Ioa_ReadParseLineOutputs( pMod, pLine ) ) + return 0; + // parse the delay info + Vec_PtrForEachEntry( pMod->vDelays, pLine, k ) + if ( !Ioa_ReadParseLineDelay( pMod, pLine ) ) + return 0; + Vec_PtrForEachEntry( pMod->vTimeInputs, pLine, k ) + if ( !Ioa_ReadParseLineTimes( pMod, pLine, 0 ) ) + return 0; + Vec_PtrForEachEntry( pMod->vTimeOutputs, pLine, k ) + if ( !Ioa_ReadParseLineTimes( pMod, pLine, 1 ) ) + return 0; + } + return 1; +} + + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static Ntl_Man_t * Ioa_ReadParse( Ioa_ReadMan_t * p ) +{ + Ntl_Man_t * pDesign; + Ioa_ReadMod_t * pMod; + char * pLine; + int i, k; + // iterate through the models + Vec_PtrForEachEntry( p->vModels, pMod, i ) + { + // parse the latches + Vec_PtrForEachEntry( pMod->vLatches, pLine, k ) + if ( !Ioa_ReadParseLineLatch( pMod, pLine ) ) + return NULL; + // parse the nodes + Vec_PtrForEachEntry( pMod->vNames, pLine, k ) + if ( !Ioa_ReadParseLineNamesBlif( pMod, pLine ) ) + return NULL; + // parse the subcircuits + Vec_PtrForEachEntry( pMod->vSubckts, pLine, k ) + if ( !Ioa_ReadParseLineSubckt( pMod, pLine ) ) + return NULL; + // finalize the network + Ntl_ModelFixNonDrivenNets( pMod->pNtk ); + } + if ( i == 0 ) + return NULL; + // update the design name + pMod = Vec_PtrEntry( p->vModels, 0 ); + if ( Ntl_ModelLatchNum(pMod->pNtk) > 0 ) + Ntl_ModelTransformLatches( pMod->pNtk ); + p->pDesign->pName = Ntl_ManStoreName( p->pDesign, pMod->pNtk->pName ); + // return the network + pDesign = p->pDesign; + p->pDesign = NULL; + return pDesign; +} + +/**Function************************************************************* + + Synopsis [Parses the model line.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static int Ioa_ReadParseLineModel( Ioa_ReadMod_t * p, char * pLine ) +{ + Vec_Ptr_t * vTokens = p->pMan->vTokens; + char * pToken; + Ioa_ReadSplitIntoTokens( vTokens, pLine, '\0' ); + pToken = Vec_PtrEntry( vTokens, 0 ); + assert( !strcmp(pToken, "model") ); + if ( Vec_PtrSize(vTokens) != 2 ) + { + sprintf( p->pMan->sError, "Line %d: The number of entries (%d) in .model line is different from two.", Ioa_ReadGetLine(p->pMan, pToken), Vec_PtrSize(vTokens) ); + return 0; + } + p->pNtk = Ntl_ModelAlloc( p->pMan->pDesign, Vec_PtrEntry(vTokens, 1) ); + if ( p->pNtk == NULL ) + { + sprintf( p->pMan->sError, "Line %d: Model %s already exists.", Ioa_ReadGetLine(p->pMan, pToken), Vec_PtrEntry(vTokens, 1) ); + return 0; + } + return 1; +} + +/**Function************************************************************* + + Synopsis [Parses the model line.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static int Ioa_ReadParseLineAttrib( Ioa_ReadMod_t * p, char * pLine ) +{ + Vec_Ptr_t * vTokens = p->pMan->vTokens; + char * pToken; + int i; + Ioa_ReadSplitIntoTokens( vTokens, pLine, '\0' ); + pToken = Vec_PtrEntry( vTokens, 0 ); + assert( !strncmp(pToken, "attrib", 6) ); + Vec_PtrForEachEntryStart( vTokens, pToken, i, 1 ) + { + pToken = Vec_PtrEntry( vTokens, i ); + if ( strcmp( pToken, "white" ) == 0 ) + p->pNtk->attrWhite = 1; + else if ( strcmp( pToken, "black" ) == 0 ) + p->pNtk->attrWhite = 0; + else if ( strcmp( pToken, "box" ) == 0 ) + p->pNtk->attrBox = 1; + else if ( strcmp( pToken, "white" ) == 0 ) + p->pNtk->attrWhite = 1; + else if ( strcmp( pToken, "comb" ) == 0 ) + p->pNtk->attrComb = 1; + else if ( strcmp( pToken, "seq" ) == 0 ) + p->pNtk->attrComb = 0; + else if ( strcmp( pToken, "keep" ) == 0 ) + p->pNtk->attrKeep = 1; + else + { + sprintf( p->pMan->sError, "Line %d: Unknown attribute (%s) in the .attrib line of model %s.", Ioa_ReadGetLine(p->pMan, pToken), pToken, p->pNtk->pName ); + return 0; + } + } + return 1; +} + +/**Function************************************************************* + + Synopsis [Parses the inputs line.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static int Ioa_ReadParseLineInputs( Ioa_ReadMod_t * p, char * pLine ) +{ + Ntl_Net_t * pNet; + Ntl_Obj_t * pObj; + Vec_Ptr_t * vTokens = p->pMan->vTokens; + char * pToken; + int i; + Ioa_ReadSplitIntoTokens( vTokens, pLine, '\0' ); + pToken = Vec_PtrEntry(vTokens, 0); + assert( !strcmp(pToken, "inputs") ); + Vec_PtrForEachEntryStart( vTokens, pToken, i, 1 ) + { + pObj = Ntl_ModelCreatePi( p->pNtk ); + pNet = Ntl_ModelFindOrCreateNet( p->pNtk, pToken ); + if ( !Ntl_ModelSetNetDriver( pObj, pNet ) ) + { + sprintf( p->pMan->sError, "Line %d: Net %s already has a driver.", Ioa_ReadGetLine(p->pMan, pToken), pNet->pName ); + return 0; + } + } + return 1; +} + +/**Function************************************************************* + + Synopsis [Parses the outputs line.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static int Ioa_ReadParseLineOutputs( Ioa_ReadMod_t * p, char * pLine ) +{ + Ntl_Net_t * pNet; + Ntl_Obj_t * pObj; + Vec_Ptr_t * vTokens = p->pMan->vTokens; + char * pToken; + int i; + Ioa_ReadSplitIntoTokens( vTokens, pLine, '\0' ); + pToken = Vec_PtrEntry(vTokens, 0); + assert( !strcmp(pToken, "outputs") ); + Vec_PtrForEachEntryStart( vTokens, pToken, i, 1 ) + { + pNet = Ntl_ModelFindOrCreateNet( p->pNtk, pToken ); + pObj = Ntl_ModelCreatePo( p->pNtk, pNet ); + } + return 1; +} + +/**Function************************************************************* + + Synopsis [Parses the latches line.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static int Ioa_ReadParseLineLatch( Ioa_ReadMod_t * p, char * pLine ) +{ + Vec_Ptr_t * vTokens = p->pMan->vTokens; + Ntl_Net_t * pNetLi, * pNetLo; + Ntl_Obj_t * pObj; + char * pToken, * pNameLi, * pNameLo; + Ioa_ReadSplitIntoTokens( vTokens, pLine, '\0' ); + pToken = Vec_PtrEntry(vTokens,0); + assert( !strcmp(pToken, "latch") ); + if ( Vec_PtrSize(vTokens) < 3 ) + { + sprintf( p->pMan->sError, "Line %d: Latch does not have input name and output name.", Ioa_ReadGetLine(p->pMan, pToken) ); + return 0; + } + // create latch + pNameLi = Vec_PtrEntry( vTokens, 1 ); + pNameLo = Vec_PtrEntry( vTokens, 2 ); + pNetLi = Ntl_ModelFindOrCreateNet( p->pNtk, pNameLi ); + pNetLo = Ntl_ModelFindOrCreateNet( p->pNtk, pNameLo ); + pObj = Ntl_ModelCreateLatch( p->pNtk ); + pObj->pFanio[0] = pNetLi; + if ( !Ntl_ModelSetNetDriver( pObj, pNetLo ) ) + { + sprintf( p->pMan->sError, "Line %d: Net %s already has a driver.", Ioa_ReadGetLine(p->pMan, pToken), pNetLo->pName ); + return 0; + } + // get initial value + if ( Vec_PtrSize(vTokens) > 3 ) + pObj->LatchId.regInit = atoi( Vec_PtrEntry(vTokens,Vec_PtrSize(vTokens)-1) ); + else + pObj->LatchId.regInit = 2; + if ( pObj->LatchId.regInit < 0 || pObj->LatchId.regInit > 2 ) + { + sprintf( p->pMan->sError, "Line %d: Initial state of the latch is incorrect \"%s\".", Ioa_ReadGetLine(p->pMan, pToken), Vec_PtrEntry(vTokens,3) ); + return 0; + } + // get the register class + if ( Vec_PtrSize(vTokens) == 6 ) + { + pToken = Vec_PtrEntry(vTokens,3); + if ( strcmp( pToken, "fe" ) == 0 ) + pObj->LatchId.regType = 1; + else if ( strcmp( pToken, "re" ) == 0 ) + pObj->LatchId.regType = 2; + else if ( strcmp( pToken, "ah" ) == 0 ) + pObj->LatchId.regType = 3; + else if ( strcmp( pToken, "al" ) == 0 ) + pObj->LatchId.regType = 4; + else if ( strcmp( pToken, "as" ) == 0 ) + pObj->LatchId.regType = 5; + else if ( pToken[0] >= '0' && pToken[0] <= '9' ) + pObj->LatchId.regClass = atoi(pToken); + else + { + sprintf( p->pMan->sError, "Line %d: Type/class of the latch is incorrect \"%s\".", Ioa_ReadGetLine(p->pMan, pToken), pToken ); + return 0; + } + } + if ( pObj->LatchId.regClass < 0 || pObj->LatchId.regClass > (1<<24) ) + { + sprintf( p->pMan->sError, "Line %d: Class of the latch is incorrect \"%s\".", Ioa_ReadGetLine(p->pMan, pToken), Vec_PtrEntry(vTokens,3) ); + return 0; + } + // get the clock + if ( Vec_PtrSize(vTokens) == 5 || Vec_PtrSize(vTokens) == 6 ) + { + pToken = Vec_PtrEntry(vTokens,Vec_PtrSize(vTokens)-2); + pNetLi = Ntl_ModelFindOrCreateNet( p->pNtk, pToken ); + pObj->pClock = pNetLi; + } + return 1; +} + +/**Function************************************************************* + + Synopsis [Parses the subckt line.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static int Ioa_ReadParseLineSubckt( Ioa_ReadMod_t * p, char * pLine ) +{ + Vec_Ptr_t * vTokens = p->pMan->vTokens; + Ntl_Mod_t * pModel; + Ntl_Obj_t * pBox, * pTerm; + Ntl_Net_t * pNet; + char * pToken, * pName, ** ppNames; + int nEquals, i, k; + + // split the line into tokens + nEquals = Ioa_ReadCountChars( pLine, '=' ); + Ioa_ReadSplitIntoTokensAndClear( vTokens, pLine, '\0', '=' ); + pToken = Vec_PtrEntry(vTokens,0); + assert( !strcmp(pToken, "subckt") ); + + // get the model for this box + pName = Vec_PtrEntry(vTokens,1); + pModel = Ntl_ManFindModel( p->pMan->pDesign, pName ); + if ( pModel == NULL ) + { + sprintf( p->pMan->sError, "Line %d: Cannot find the model for subcircuit %s.", Ioa_ReadGetLine(p->pMan, pToken), pName ); + return 0; + } +/* + // temporary fix for splitting the .subckt line + if ( nEquals < Ntl_ModelPiNum(pModel) + Ntl_ModelPoNum(pModel) ) + { + Vec_Ptr_t * vTokens2 = Vec_PtrAlloc( 10 ); + // get one additional token + pToken = Vec_PtrEntry( vTokens, Vec_PtrSize(vTokens) - 1 ); + for ( ; *pToken; pToken++ ); + for ( ; *pToken == 0; pToken++ ); + Ioa_ReadSplitIntoTokensAndClear( vTokens2, pToken, '\0', '=' ); +// assert( Vec_PtrSize( vTokens2 ) == 2 ); + Vec_PtrForEachEntry( vTokens2, pToken, i ) + Vec_PtrPush( vTokens, pToken ); + nEquals += Vec_PtrSize(vTokens2)/2; + Vec_PtrFree( vTokens2 ); + } +*/ + // check if the number of tokens is correct + if ( nEquals != Ntl_ModelPiNum(pModel) + Ntl_ModelPoNum(pModel) ) + { + sprintf( p->pMan->sError, "Line %d: The number of ports (%d) in .subckt %s differs from the sum of PIs and POs of the model (%d).", + Ioa_ReadGetLine(p->pMan, pToken), nEquals, pName, Ntl_ModelPiNum(pModel) + Ntl_ModelPoNum(pModel) ); + return 0; + } + + // get the names + ppNames = (char **)Vec_PtrArray(vTokens) + 2; + + // create the box with these terminals + pBox = Ntl_ModelCreateBox( p->pNtk, Ntl_ModelPiNum(pModel), Ntl_ModelPoNum(pModel) ); + pBox->pImplem = pModel; + Ntl_ModelForEachPi( pModel, pTerm, i ) + { + // find this terminal among the formal inputs of the subcircuit + pName = Ntl_ObjFanout0(pTerm)->pName; + for ( k = 0; k < nEquals; k++ ) + if ( !strcmp( ppNames[2*k], pName ) ) + break; + if ( k == nEquals ) + { + sprintf( p->pMan->sError, "Line %d: Cannot find PI \"%s\" of the model \"%s\" as a formal input of the subcircuit.", + Ioa_ReadGetLine(p->pMan, pToken), pName, pModel->pName ); + return 0; + } + // create the BI with the actual name + pNet = Ntl_ModelFindOrCreateNet( p->pNtk, ppNames[2*k+1] ); + Ntl_ObjSetFanin( pBox, pNet, i ); + } + Ntl_ModelForEachPo( pModel, pTerm, i ) + { + // find this terminal among the formal outputs of the subcircuit + pName = Ntl_ObjFanin0(pTerm)->pName; + for ( k = 0; k < nEquals; k++ ) + if ( !strcmp( ppNames[2*k], pName ) ) + break; + if ( k == nEquals ) + { + sprintf( p->pMan->sError, "Line %d: Cannot find PO \"%s\" of the model \"%s\" as a formal output of the subcircuit.", + Ioa_ReadGetLine(p->pMan, pToken), pName, pModel->pName ); + return 0; + } + // create the BI with the actual name + pNet = Ntl_ModelFindOrCreateNet( p->pNtk, ppNames[2*k+1] ); + Ntl_ObjSetFanout( pBox, pNet, i ); + } + return 1; +} + +/**Function************************************************************* + + Synopsis [Parses the subckt line.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static int Ioa_ReadParseLineDelay( Ioa_ReadMod_t * p, char * pLine ) +{ + Vec_Ptr_t * vTokens = p->pMan->vTokens; + int RetValue1, RetValue2, Number1, Number2, Temp; + char * pToken, * pTokenNum; + float Delay; + assert( sizeof(float) == sizeof(int) ); + Ioa_ReadSplitIntoTokens( vTokens, pLine, '\0' ); + pToken = Vec_PtrEntry(vTokens,0); + assert( !strcmp(pToken, "delay") ); + if ( Vec_PtrSize(vTokens) < 2 && Vec_PtrSize(vTokens) > 4 ) + { + sprintf( p->pMan->sError, "Line %d: Delay line does not have a valid number of parameters (1, 2, or 3).", Ioa_ReadGetLine(p->pMan, pToken) ); + return 0; + } + // find the delay number + pTokenNum = Vec_PtrEntryLast(vTokens); + Delay = atof( pTokenNum ); + if ( Delay == 0.0 && pTokenNum[0] != '0' ) + { + sprintf( p->pMan->sError, "Line %d: Delay value (%s) appears to be invalid.", Ioa_ReadGetLine(p->pMan, pToken), Vec_PtrEntryLast(vTokens) ); + return 0; + } + // find the PI/PO numbers + RetValue1 = 0; Number1 = -1; + if ( Vec_PtrSize(vTokens) > 2 ) + { + RetValue1 = Ntl_ModelFindPioNumber( p->pNtk, 0, 0, Vec_PtrEntry(vTokens, 1), &Number1 ); + if ( RetValue1 == 0 ) + { + sprintf( p->pMan->sError, "Line %d: Cannot find signal \"%s\" among PIs/POs.", Ioa_ReadGetLine(p->pMan, pToken), Vec_PtrEntry(vTokens, 1) ); + return 0; + } + } + RetValue2 = 0; Number2 = -1; + if ( Vec_PtrSize(vTokens) > 3 ) + { + RetValue2 = Ntl_ModelFindPioNumber( p->pNtk, 0, 0, Vec_PtrEntry(vTokens, 2), &Number2 ); + if ( RetValue2 == 0 ) + { + sprintf( p->pMan->sError, "Line %d: Cannot find signal \"%s\" among PIs/POs.", Ioa_ReadGetLine(p->pMan, pToken), Vec_PtrEntry(vTokens, 2) ); + return 0; + } + } + if ( RetValue1 == RetValue2 && RetValue1 ) + { + sprintf( p->pMan->sError, "Line %d: Both signals \"%s\" and \"%s\" listed appear to be PIs or POs.", + Ioa_ReadGetLine(p->pMan, pToken), Vec_PtrEntry(vTokens, 1), Vec_PtrEntry(vTokens, 2) ); + return 0; + } + if ( RetValue2 < RetValue1 ) + { + Temp = RetValue2; RetValue2 = RetValue1; RetValue1 = Temp; + Temp = Number2; Number2 = Number1; Number1 = Temp; + } + assert( RetValue1 == 0 || RetValue1 == -1 ); + assert( RetValue2 == 0 || RetValue2 == 1 ); + // store the values + if ( p->pNtk->vDelays == NULL ) + p->pNtk->vDelays = Vec_IntAlloc( 100 ); + Vec_IntPush( p->pNtk->vDelays, Number1 ); + Vec_IntPush( p->pNtk->vDelays, Number2 ); + Vec_IntPush( p->pNtk->vDelays, Aig_Float2Int(Delay) ); + return 1; +} + +/**Function************************************************************* + + Synopsis [Parses the subckt line.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static int Ioa_ReadParseLineTimes( Ioa_ReadMod_t * p, char * pLine, int fOutput ) +{ + Vec_Ptr_t * vTokens = p->pMan->vTokens; + int RetValue, Number = -1; + char * pToken, * pTokenNum; + float Delay; + assert( sizeof(float) == sizeof(int) ); + Ioa_ReadSplitIntoTokens( vTokens, pLine, '\0' ); + pToken = Vec_PtrEntry(vTokens,0); + if ( fOutput ) + assert( !strncmp(pToken, "output_", 7) ); + else + assert( !strncmp(pToken, "input_", 6) ); + if ( Vec_PtrSize(vTokens) != 2 && Vec_PtrSize(vTokens) != 3 ) + { + sprintf( p->pMan->sError, "Line %d: Delay line does not have a valid number of parameters (2 or 3).", Ioa_ReadGetLine(p->pMan, pToken) ); + return 0; + } + // find the delay number + pTokenNum = Vec_PtrEntryLast(vTokens); + if ( !strcmp( pTokenNum, "-inf" ) ) + Delay = -TIM_ETERNITY; + else if ( !strcmp( pTokenNum, "inf" ) ) + Delay = TIM_ETERNITY; + else + Delay = atof( pTokenNum ); + if ( Delay == 0.0 && pTokenNum[0] != '0' ) + { + sprintf( p->pMan->sError, "Line %d: Delay value (%s) appears to be invalid.", Ioa_ReadGetLine(p->pMan, pToken), Vec_PtrEntryLast(vTokens) ); + return 0; + } + // find the PI/PO numbers + if ( fOutput ) + { + if ( Vec_PtrSize(vTokens) == 3 ) + { + RetValue = Ntl_ModelFindPioNumber( p->pNtk, 0, 1, Vec_PtrEntry(vTokens, 1), &Number ); + if ( RetValue == 0 ) + { + sprintf( p->pMan->sError, "Line %d: Cannot find signal \"%s\" among POs.", Ioa_ReadGetLine(p->pMan, pToken), Vec_PtrEntry(vTokens, 1) ); + return 0; + } + } + // store the values + if ( p->pNtk->vTimeOutputs == NULL ) + p->pNtk->vTimeOutputs = Vec_IntAlloc( 100 ); + Vec_IntPush( p->pNtk->vTimeOutputs, Number ); + Vec_IntPush( p->pNtk->vTimeOutputs, Aig_Float2Int(Delay) ); + } + else + { + if ( Vec_PtrSize(vTokens) == 3 ) + { + RetValue = Ntl_ModelFindPioNumber( p->pNtk, 1, 0, Vec_PtrEntry(vTokens, 1), &Number ); + if ( RetValue == 0 ) + { + sprintf( p->pMan->sError, "Line %d: Cannot find signal \"%s\" among PIs.", Ioa_ReadGetLine(p->pMan, pToken), Vec_PtrEntry(vTokens, 1) ); + return 0; + } + } + // store the values + if ( p->pNtk->vTimeInputs == NULL ) + p->pNtk->vTimeInputs = Vec_IntAlloc( 100 ); + Vec_IntPush( p->pNtk->vTimeInputs, Number ); + Vec_IntPush( p->pNtk->vTimeInputs, Aig_Float2Int(Delay) ); + } + return 1; +} + + +/**Function************************************************************* + + Synopsis [Constructs the SOP cover from the file parsing info.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static char * Ioa_ReadParseTableBlif( Ioa_ReadMod_t * p, char * pTable, int nFanins ) +{ + Vec_Ptr_t * vTokens = p->pMan->vTokens; + Vec_Str_t * vFunc = p->pMan->vFunc; + char * pProduct, * pOutput; + int i, Polarity = -1; + + p->pMan->nTablesRead++; + // get the tokens + Ioa_ReadSplitIntoTokens( vTokens, pTable, '.' ); + if ( Vec_PtrSize(vTokens) == 0 ) + return Ntl_ManStoreSop( p->pMan->pDesign->pMemSops, " 0\n" ); + if ( Vec_PtrSize(vTokens) == 1 ) + { + pOutput = Vec_PtrEntry( vTokens, 0 ); + if ( ((pOutput[0] - '0') & 0x8E) || pOutput[1] ) + { + sprintf( p->pMan->sError, "Line %d: Constant table has wrong output value \"%s\".", Ioa_ReadGetLine(p->pMan, pOutput), pOutput ); + return NULL; + } + return Ntl_ManStoreSop( p->pMan->pDesign->pMemSops, (pOutput[0] == '0') ? " 0\n" : " 1\n" ); + } + pProduct = Vec_PtrEntry( vTokens, 0 ); + if ( Vec_PtrSize(vTokens) % 2 == 1 ) + { + sprintf( p->pMan->sError, "Line %d: Table has odd number of tokens (%d).", Ioa_ReadGetLine(p->pMan, pProduct), Vec_PtrSize(vTokens) ); + return NULL; + } + // parse the table + Vec_StrClear( vFunc ); + for ( i = 0; i < Vec_PtrSize(vTokens)/2; i++ ) + { + pProduct = Vec_PtrEntry( vTokens, 2*i + 0 ); + pOutput = Vec_PtrEntry( vTokens, 2*i + 1 ); + if ( strlen(pProduct) != (unsigned)nFanins ) + { + sprintf( p->pMan->sError, "Line %d: Cube \"%s\" has size different from the fanin count (%d).", Ioa_ReadGetLine(p->pMan, pProduct), pProduct, nFanins ); + return NULL; + } + if ( ((pOutput[0] - '0') & 0x8E) || pOutput[1] ) + { + sprintf( p->pMan->sError, "Line %d: Output value \"%s\" is incorrect.", Ioa_ReadGetLine(p->pMan, pProduct), pOutput ); + return NULL; + } + if ( Polarity == -1 ) + Polarity = pOutput[0] - '0'; + else if ( Polarity != pOutput[0] - '0' ) + { + sprintf( p->pMan->sError, "Line %d: Output value \"%s\" differs from the value in the first line of the table (%d).", Ioa_ReadGetLine(p->pMan, pProduct), pOutput, Polarity ); + return NULL; + } + // parse one product + Vec_StrAppend( vFunc, pProduct ); + Vec_StrPush( vFunc, ' ' ); + Vec_StrPush( vFunc, pOutput[0] ); + Vec_StrPush( vFunc, '\n' ); + } + Vec_StrPush( vFunc, '\0' ); + return Vec_StrArray( vFunc ); +} + +/**Function************************************************************* + + Synopsis [Parses the nodes line.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static int Ioa_ReadParseLineNamesBlif( Ioa_ReadMod_t * p, char * pLine ) +{ + Vec_Ptr_t * vTokens = p->pMan->vTokens; + Ntl_Obj_t * pNode; + Ntl_Net_t * pNetOut, * pNetIn; + char * pNameOut, * pNameIn; + int i; + Ioa_ReadSplitIntoTokens( vTokens, pLine, '\0' ); + // parse the mapped node +// if ( !strcmp(Vec_PtrEntry(vTokens,0), "gate") ) +// return Ioa_ReadParseLineGateBlif( p, vTokens ); + // parse the regular name line + assert( !strcmp(Vec_PtrEntry(vTokens,0), "names") ); + pNameOut = Vec_PtrEntryLast( vTokens ); + pNetOut = Ntl_ModelFindOrCreateNet( p->pNtk, pNameOut ); + // create fanins + pNode = Ntl_ModelCreateNode( p->pNtk, Vec_PtrSize(vTokens) - 2 ); + for ( i = 0; i < Vec_PtrSize(vTokens) - 2; i++ ) + { + pNameIn = Vec_PtrEntry(vTokens, i+1); + pNetIn = Ntl_ModelFindOrCreateNet( p->pNtk, pNameIn ); + Ntl_ObjSetFanin( pNode, pNetIn, i ); + } + if ( !Ntl_ModelSetNetDriver( pNode, pNetOut ) ) + { + sprintf( p->pMan->sError, "Line %d: Signal \"%s\" is defined more than once.", Ioa_ReadGetLine(p->pMan, pNameOut), pNameOut ); + return 0; + } + // parse the table of this node + pNode->pSop = Ioa_ReadParseTableBlif( p, pNameOut + strlen(pNameOut), pNode->nFanins ); + if ( pNode->pSop == NULL ) + return 0; + pNode->pSop = Ntl_ManStoreSop( p->pNtk->pMan->pMemSops, pNode->pSop ); + return 1; +} + + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + + diff --git a/src/aig/ntl/ntlTime.c b/src/aig/ntl/ntlTime.c index 53603cee..ee3e489b 100644 --- a/src/aig/ntl/ntlTime.c +++ b/src/aig/ntl/ntlTime.c @@ -91,6 +91,7 @@ void Ntl_ManUnpackLeafTiming( Ntl_Man_t * p, Tim_Man_t * pMan ) pNet->dTemp = 0; // store the PI timing vTimes = pRoot->vTimeInputs; + if ( vTimes ) Vec_IntForEachEntry( vTimes, Entry, i ) { dTime = Aig_Int2Float( Vec_IntEntry(vTimes,++i) ); @@ -172,7 +173,7 @@ Tim_Man_t * Ntl_ManCreateTiming( Ntl_Man_t * p ) Vec_Ptr_t * vDelayTables; Ntl_Mod_t * pRoot, * pModel; Ntl_Obj_t * pObj; - int i, curPi, iBox, Entry; + int i, curPi, iBox;//, Entry; assert( p->pAig != NULL ); pRoot = Ntl_ManRootModel( p ); // start the timing manager diff --git a/src/aig/ntl/ntlUtil.c b/src/aig/ntl/ntlUtil.c index 1fb9f1c6..4fd1762c 100644 --- a/src/aig/ntl/ntlUtil.c +++ b/src/aig/ntl/ntlUtil.c @@ -402,14 +402,23 @@ Vec_Vec_t * Ntl_ManTransformRegClasses( Ntl_Man_t * pMan, int nSizeMax, int fVer { printf( "The number of register clases = %d.\n", nClasses ); for ( i = 0; i <= ClassMax; i++ ) - printf( "%d:%d ", Class, pClassNums[i] ); + if ( pClassNums[i] ) + printf( "%d:%d ", i, pClassNums[i] ); printf( "\n" ); } // skip if there is only one class if ( nClasses == 1 ) { + vParts = NULL; + if ( Vec_IntSize(pMan->vRegClasses) >= nSizeMax ) + { + vParts = Vec_PtrAlloc( 100 ); + vPart = Vec_IntStartNatural( Vec_IntSize(pMan->vRegClasses) ); + Vec_PtrPush( vParts, vPart ); + } + printf( "There is only one clock domain with %d registers.\n", Vec_IntSize(pMan->vRegClasses) ); free( pClassNums ); - return NULL; + return (Vec_Vec_t *)vParts; } // create classes vParts = Vec_PtrAlloc( 100 ); diff --git a/src/aig/ntl/ntlWriteBlif.c b/src/aig/ntl/ntlWriteBlif.c index f93e3fa1..8c97d3d0 100644 --- a/src/aig/ntl/ntlWriteBlif.c +++ b/src/aig/ntl/ntlWriteBlif.c @@ -21,6 +21,13 @@ #include "ntl.h" #include "ioa.h" +#include <bzlib.h> +#include <stdarg.h> + +#ifdef _WIN32 +#define vsnprintf _vsnprintf +#endif + //////////////////////////////////////////////////////////////////////// /// DECLARATIONS /// //////////////////////////////////////////////////////////////////////// @@ -181,7 +188,7 @@ void Ioa_WriteBlifModel( FILE * pFile, Ntl_Mod_t * pModel, int fMain ) SeeAlso [] ***********************************************************************/ -void Ioa_WriteBlif( Ntl_Man_t * p, char * pFileName ) +void Ioa_WriteBlif_old( Ntl_Man_t * p, char * pFileName ) { FILE * pFile; Ntl_Mod_t * pModel; @@ -220,6 +227,264 @@ void Ioa_WriteBlifLogic( Nwk_Man_t * pNtk, Ntl_Man_t * p, char * pFileName ) Ntl_ManFree( pNew ); } + + +/**Function************************************************************* + + Synopsis [Procedure to write data into BZ2 file.] + + Description [Based on the vsnprintf() man page.] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +typedef struct bz2file { + FILE * f; + BZFILE * b; + char * buf; + int nBytes; + int nBytesMax; +} bz2file; + +int fprintfBz2(bz2file * b, char * fmt, ...) { + if (b->b) { + char * newBuf; + int bzError; + va_list ap; + while (1) { + va_start(ap,fmt); + b->nBytes = vsnprintf(b->buf,b->nBytesMax,fmt,ap); + va_end(ap); + if (b->nBytes > -1 && b->nBytes < b->nBytesMax) + break; + if (b->nBytes > -1) + b->nBytesMax = b->nBytes + 1; + else + b->nBytesMax *= 2; + if ((newBuf = REALLOC( char,b->buf,b->nBytesMax )) == NULL) + return -1; + else + b->buf = newBuf; + } + BZ2_bzWrite( &bzError, b->b, b->buf, b->nBytes ); + if (bzError == BZ_IO_ERROR) { + fprintf( stdout, "Ioa_WriteBlif(): I/O error writing to compressed stream.\n" ); + return -1; + } + return b->nBytes; + } else { + int n; + va_list ap; + va_start(ap,fmt); + n = vfprintf( b->f, fmt, ap); + va_end(ap); + return n; + } +} + + +/**Function************************************************************* + + Synopsis [Writes one model into the BLIF file.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Ioa_WriteBlifModelBz2( bz2file * b, Ntl_Mod_t * pModel, int fMain ) +{ + Ntl_Obj_t * pObj; + Ntl_Net_t * pNet; + float Delay; + int i, k; + fprintfBz2( b, ".model %s\n", pModel->pName ); + if ( pModel->attrWhite || pModel->attrBox || pModel->attrComb || pModel->attrKeep ) + { + fprintfBz2( b, ".attrib" ); + fprintfBz2( b, " %s", pModel->attrWhite? "white": "black" ); + fprintfBz2( b, " %s", pModel->attrBox? "box" : "logic" ); + fprintfBz2( b, " %s", pModel->attrComb? "comb" : "seq" ); +// fprintfBz2( b, " %s", pModel->attrKeep? "keep" : "sweep" ); + fprintfBz2( b, "\n" ); + } + fprintfBz2( b, ".inputs" ); + Ntl_ModelForEachPi( pModel, pObj, i ) + fprintfBz2( b, " %s", Ntl_ObjFanout0(pObj)->pName ); + fprintfBz2( b, "\n" ); + fprintfBz2( b, ".outputs" ); + Ntl_ModelForEachPo( pModel, pObj, i ) + fprintfBz2( b, " %s", Ntl_ObjFanin0(pObj)->pName ); + fprintfBz2( b, "\n" ); + // write delays + if ( pModel->vDelays ) + { + for ( i = 0; i < Vec_IntSize(pModel->vDelays); i += 3 ) + { + fprintfBz2( b, ".delay" ); + if ( Vec_IntEntry(pModel->vDelays,i) != -1 ) + fprintfBz2( b, " %s", Ntl_ObjFanout0(Ntl_ModelPi(pModel, Vec_IntEntry(pModel->vDelays,i)))->pName ); + if ( Vec_IntEntry(pModel->vDelays,i+1) != -1 ) + fprintfBz2( b, " %s", Ntl_ObjFanin0(Ntl_ModelPo(pModel, Vec_IntEntry(pModel->vDelays,i+1)))->pName ); + fprintfBz2( b, " %.3f", Aig_Int2Float(Vec_IntEntry(pModel->vDelays,i+2)) ); + fprintfBz2( b, "\n" ); + } + } + if ( pModel->vTimeInputs ) + { + for ( i = 0; i < Vec_IntSize(pModel->vTimeInputs); i += 2 ) + { + if ( fMain ) + fprintfBz2( b, ".input_arrival" ); + else + fprintfBz2( b, ".input_required" ); + if ( Vec_IntEntry(pModel->vTimeInputs,i) != -1 ) + fprintfBz2( b, " %s", Ntl_ObjFanout0(Ntl_ModelPi(pModel, Vec_IntEntry(pModel->vTimeInputs,i)))->pName ); + Delay = Aig_Int2Float(Vec_IntEntry(pModel->vTimeInputs,i+1)); + if ( Delay == -TIM_ETERNITY ) + fprintfBz2( b, " -inf" ); + else if ( Delay == TIM_ETERNITY ) + fprintfBz2( b, " inf" ); + else + fprintfBz2( b, " %.3f", Delay ); + fprintfBz2( b, "\n" ); + } + } + if ( pModel->vTimeOutputs ) + { + for ( i = 0; i < Vec_IntSize(pModel->vTimeOutputs); i += 2 ) + { + if ( fMain ) + fprintfBz2( b, ".output_required" ); + else + fprintfBz2( b, ".output_arrival" ); + if ( Vec_IntEntry(pModel->vTimeOutputs,i) != -1 ) + fprintfBz2( b, " %s", Ntl_ObjFanin0(Ntl_ModelPo(pModel, Vec_IntEntry(pModel->vTimeOutputs,i)))->pName ); + Delay = Aig_Int2Float(Vec_IntEntry(pModel->vTimeOutputs,i+1)); + if ( Delay == -TIM_ETERNITY ) + fprintfBz2( b, " -inf" ); + else if ( Delay == TIM_ETERNITY ) + fprintfBz2( b, " inf" ); + else + fprintfBz2( b, " %.3f", Delay ); + fprintfBz2( b, "\n" ); + } + } + // write objects + Ntl_ModelForEachObj( pModel, pObj, i ) + { + if ( Ntl_ObjIsNode(pObj) ) + { + fprintfBz2( b, ".names" ); + Ntl_ObjForEachFanin( pObj, pNet, k ) + fprintfBz2( b, " %s", pNet->pName ); + fprintfBz2( b, " %s\n", Ntl_ObjFanout0(pObj)->pName ); + fprintfBz2( b, "%s", pObj->pSop ); + } + else if ( Ntl_ObjIsLatch(pObj) ) + { + fprintfBz2( b, ".latch" ); + fprintfBz2( b, " %s", Ntl_ObjFanin0(pObj)->pName ); + fprintfBz2( b, " %s", Ntl_ObjFanout0(pObj)->pName ); + assert( pObj->LatchId.regType == 0 || pObj->LatchId.regClass == 0 ); + if ( pObj->LatchId.regType ) + { + if ( pObj->LatchId.regType == 1 ) + fprintfBz2( b, " fe" ); + else if ( pObj->LatchId.regType == 2 ) + fprintfBz2( b, " re" ); + else if ( pObj->LatchId.regType == 3 ) + fprintfBz2( b, " ah" ); + else if ( pObj->LatchId.regType == 4 ) + fprintfBz2( b, " al" ); + else if ( pObj->LatchId.regType == 5 ) + fprintfBz2( b, " as" ); + else + assert( 0 ); + } + else if ( pObj->LatchId.regClass ) + fprintfBz2( b, " %d", pObj->LatchId.regClass ); + if ( pObj->pClock ) + fprintfBz2( b, " %s", pObj->pClock->pName ); + fprintfBz2( b, " %d", pObj->LatchId.regInit ); + fprintfBz2( b, "\n" ); + } + else if ( Ntl_ObjIsBox(pObj) ) + { + fprintfBz2( b, ".subckt %s", pObj->pImplem->pName ); + Ntl_ObjForEachFanin( pObj, pNet, k ) + fprintfBz2( b, " %s=%s", Ntl_ModelPiName(pObj->pImplem, k), pNet->pName ); + Ntl_ObjForEachFanout( pObj, pNet, k ) + fprintfBz2( b, " %s=%s", Ntl_ModelPoName(pObj->pImplem, k), pNet->pName ); + fprintfBz2( b, "\n" ); + } + } + fprintfBz2( b, ".end\n\n" ); +} + +/**Function************************************************************* + + Synopsis [Writes the logic network into the BLIF file.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Ioa_WriteBlif( Ntl_Man_t * p, char * pFileName ) +{ + Ntl_Mod_t * pModel; + int i, bzError; + + bz2file b; + memset(&b,0,sizeof(b)); + b.nBytesMax = (1<<12); + b.buf = ALLOC( char,b.nBytesMax ); + + // start the output stream + b.f = fopen( pFileName, "wb" ); + if ( b.f == NULL ) + { + fprintf( stdout, "Ioa_WriteBlif(): Cannot open the output file \"%s\".\n", pFileName ); + FREE(b.buf); + return; + } + if (!strncmp(pFileName+strlen(pFileName)-4,".bz2",4)) { + b.b = BZ2_bzWriteOpen( &bzError, b.f, 9, 0, 0 ); + if ( bzError != BZ_OK ) { + BZ2_bzWriteClose( &bzError, b.b, 0, NULL, NULL ); + fprintf( stdout, "Ioa_WriteBlif(): Cannot start compressed stream.\n" ); + fclose( b.f ); + FREE(b.buf); + return; + } + } + + fprintfBz2( &b, "# Benchmark \"%s\" written by ABC-8 on %s\n", p->pName, Ioa_TimeStamp() ); + // write the models + Ntl_ManForEachModel( p, pModel, i ) + Ioa_WriteBlifModelBz2( &b, pModel, i==0 ); + // close the file + if (b.b) { + BZ2_bzWriteClose( &bzError, b.b, 0, NULL, NULL ); + if (bzError == BZ_IO_ERROR) { + fprintf( stdout, "Ioa_WriteBlif(): I/O error closing compressed stream.\n" ); + fclose( b.f ); + FREE(b.buf); + return; + } + } + fclose( b.f ); + FREE(b.buf); +} + + //////////////////////////////////////////////////////////////////////// /// END OF FILE /// //////////////////////////////////////////////////////////////////////// diff --git a/src/base/abci/abc.c b/src/base/abci/abc.c index db8d7327..d3372c9a 100644 --- a/src/base/abci/abc.c +++ b/src/base/abci/abc.c @@ -17462,22 +17462,23 @@ int Abc_CommandAbc8Ssw( Abc_Frame_t * pAbc, int argc, char ** argv ) extern int Ntl_ManIsComb( void * p ); // set defaults - pPars->nPartSize = 0; - pPars->nOverSize = 0; - pPars->nFramesP = 0; - pPars->nFramesK = 1; - pPars->nMaxImps = 5000; - pPars->nMaxLevs = 0; - pPars->fUseImps = 0; - pPars->fRewrite = 0; - pPars->fFraiging = 0; - pPars->fLatchCorr = 0; - pPars->fWriteImps = 0; - pPars->fUse1Hot = 0; - pPars->fVerbose = 0; - pPars->TimeLimit = 0; + pPars->nPartSize = 0; + pPars->nOverSize = 0; + pPars->nFramesP = 0; + pPars->nFramesK = 1; + pPars->nMaxImps = 5000; + pPars->nMaxLevs = 0; + pPars->nMinDomSize = 100; + pPars->fUseImps = 0; + pPars->fRewrite = 0; + pPars->fFraiging = 0; + pPars->fLatchCorr = 0; + pPars->fWriteImps = 0; + pPars->fUse1Hot = 0; + pPars->fVerbose = 0; + pPars->TimeLimit = 0; Extra_UtilGetoptReset(); - while ( ( c = Extra_UtilGetopt( argc, argv, "PQNFILirfletvh" ) ) != EOF ) + while ( ( c = Extra_UtilGetopt( argc, argv, "PQNFILCirfletvh" ) ) != EOF ) { switch ( c ) { @@ -17547,6 +17548,17 @@ int Abc_CommandAbc8Ssw( Abc_Frame_t * pAbc, int argc, char ** argv ) if ( pPars->nMaxLevs <= 0 ) goto usage; break; + case 'C': + if ( globalUtilOptind >= argc ) + { + fprintf( stdout, "Command line switch \"-C\" should be followed by an integer.\n" ); + goto usage; + } + pPars->nMinDomSize = atoi(argv[globalUtilOptind]); + globalUtilOptind++; + if ( pPars->nMinDomSize <= 0 ) + goto usage; + break; case 'i': pPars->fUseImps ^= 1; break; @@ -17623,13 +17635,14 @@ int Abc_CommandAbc8Ssw( Abc_Frame_t * pAbc, int argc, char ** argv ) return 0; usage: - fprintf( stdout, "usage: *ssw [-PQNFL num] [-lrfetvh]\n" ); + fprintf( stdout, "usage: *ssw [-PQNFLC num] [-lrfetvh]\n" ); fprintf( stdout, "\t performs sequential sweep using K-step induction on the netlist \n" ); fprintf( stdout, "\t-P num : max partition size (0 = no partitioning) [default = %d]\n", pPars->nPartSize ); fprintf( stdout, "\t-Q num : partition overlap (0 = no overlap) [default = %d]\n", pPars->nOverSize ); fprintf( stdout, "\t-N num : number of time frames to use as the prefix [default = %d]\n", pPars->nFramesP ); fprintf( stdout, "\t-F num : number of time frames for induction (1=simple) [default = %d]\n", pPars->nFramesK ); fprintf( stdout, "\t-L num : max number of levels to consider (0=all) [default = %d]\n", pPars->nMaxLevs ); + fprintf( stdout, "\t-C num : min size of a clock domain used for synthesis [default = %d]\n", pPars->nMinDomSize ); // fprintf( stdout, "\t-I num : max number of implications to consider [default = %d]\n", pPars->nMaxImps ); // fprintf( stdout, "\t-i : toggle using implications [default = %s]\n", pPars->fUseImps? "yes": "no" ); fprintf( stdout, "\t-l : toggle latch correspondence only [default = %s]\n", pPars->fLatchCorr? "yes": "no" ); diff --git a/src/base/io/ioReadAiger.c b/src/base/io/ioReadAiger.c index 3739205d..9ecc00fd 100644 --- a/src/base/io/ioReadAiger.c +++ b/src/base/io/ioReadAiger.c @@ -20,6 +20,7 @@ ***********************************************************************/ #include "ioAbc.h" +#include <bzlib.h> //////////////////////////////////////////////////////////////////////// /// DECLARATIONS /// @@ -85,6 +86,92 @@ Vec_Int_t * Io_WriteDecodeLiterals( char ** ppPos, int nEntries ) return vLits; } + +/**Function************************************************************* + + Synopsis [Reads the file into a character buffer.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +typedef struct buflist { + char buf[1<<20]; + int nBuf; + struct buflist * next; +} buflist; + +static char * Ioa_ReadLoadFileBz2Aig( char * pFileName ) +{ + FILE * pFile; + int nFileSize = 0; + char * pContents; + BZFILE * b; + int bzError; + struct buflist * pNext; + buflist * bufHead = NULL, * buf = NULL; + + pFile = fopen( pFileName, "rb" ); + if ( pFile == NULL ) + { + printf( "Ioa_ReadLoadFileBz2(): The file is unavailable (absent or open).\n" ); + return NULL; + } + b = BZ2_bzReadOpen(&bzError,pFile,0,0,NULL,0); + if (bzError != BZ_OK) { + printf( "Ioa_ReadLoadFileBz2(): BZ2_bzReadOpen() failed with error %d.\n",bzError ); + return NULL; + } + do { + if (!bufHead) + buf = bufHead = ALLOC( buflist, 1 ); + else + buf = buf->next = ALLOC( buflist, 1 ); + nFileSize += buf->nBuf = BZ2_bzRead(&bzError,b,buf->buf,1<<20); + buf->next = NULL; + } while (bzError == BZ_OK); + if (bzError == BZ_STREAM_END) { + // we're okay + char * p; + int nBytes = 0; + BZ2_bzReadClose(&bzError,b); + p = pContents = ALLOC( char, nFileSize + 10 ); + buf = bufHead; + do { + memcpy(p+nBytes,buf->buf,buf->nBuf); + nBytes += buf->nBuf; +// } while((buf = buf->next)); + pNext = buf->next; + free( buf ); + } while((buf = pNext)); + } else if (bzError == BZ_DATA_ERROR_MAGIC) { + // not a BZIP2 file + BZ2_bzReadClose(&bzError,b); + fseek( pFile, 0, SEEK_END ); + nFileSize = ftell( pFile ); + if ( nFileSize == 0 ) + { + printf( "Ioa_ReadLoadFileBz2(): The file is empty.\n" ); + return NULL; + } + pContents = ALLOC( char, nFileSize + 10 ); + rewind( pFile ); + fread( pContents, nFileSize, 1, pFile ); + } else { + // Some other error. + printf( "Ioa_ReadLoadFileBz2(): Unable to read the compressed BLIF.\n" ); + return NULL; + } + fclose( pFile ); + // finish off the file with the spare .end line + // some benchmarks suddenly break off without this line + strcpy( pContents + nFileSize, "\n.end\n" ); + return pContents; +} + /**Function************************************************************* Synopsis [Reads the AIG in the binary AIGER format.] @@ -109,11 +196,18 @@ Abc_Ntk_t * Io_ReadAiger( char * pFileName, int fCheck ) unsigned uLit0, uLit1, uLit; // read the file into the buffer - nFileSize = Extra_FileSize( pFileName ); - pFile = fopen( pFileName, "rb" ); - pContents = ALLOC( char, nFileSize ); - fread( pContents, nFileSize, 1, pFile ); - fclose( pFile ); + if ( !strncmp(pFileName+strlen(pFileName)-4,".bz2",4) ) + pContents = Ioa_ReadLoadFileBz2Aig( pFileName ); + else + { +// pContents = Ioa_ReadLoadFile( pFileName ); + nFileSize = Extra_FileSize( pFileName ); + pFile = fopen( pFileName, "rb" ); + pContents = ALLOC( char, nFileSize ); + fread( pContents, nFileSize, 1, pFile ); + fclose( pFile ); + } + // check if the input file format is correct if ( strncmp(pContents, "aig", 3) != 0 || (pContents[3] != ' ' && pContents[3] != '2') ) diff --git a/src/base/io/ioWriteAiger.c b/src/base/io/ioWriteAiger.c index fb107e77..9e5ee8b4 100644 --- a/src/base/io/ioWriteAiger.c +++ b/src/base/io/ioWriteAiger.c @@ -21,6 +21,13 @@ #include "ioAbc.h" +#include <bzlib.h> +#include <stdarg.h> + +#ifdef _WIN32 +#define vsnprintf _vsnprintf +#endif + //////////////////////////////////////////////////////////////////////// /// DECLARATIONS /// //////////////////////////////////////////////////////////////////////// @@ -248,7 +255,7 @@ Vec_Str_t * Io_WriteEncodeLiterals( Vec_Int_t * vLits ) SeeAlso [] ***********************************************************************/ -void Io_WriteAiger( Abc_Ntk_t * pNtk, char * pFileName, int fWriteSymbols, int fCompact ) +void Io_WriteAiger_old( Abc_Ntk_t * pNtk, char * pFileName, int fWriteSymbols, int fCompact ) { ProgressBar * pProgress; FILE * pFile; @@ -258,6 +265,13 @@ void Io_WriteAiger( Abc_Ntk_t * pNtk, char * pFileName, int fWriteSymbols, int f unsigned uLit0, uLit1, uLit; assert( Abc_NtkIsStrash(pNtk) ); + Abc_NtkForEachLatch( pNtk, pObj, i ) + if ( !Abc_LatchIsInit0(pObj) ) + { + fprintf( stdout, "Io_WriteAiger(): Cannot write AIGER format with non-0 latch init values. Run \"zero\".\n" ); + return; + } + // start the output stream pFile = fopen( pFileName, "wb" ); if ( pFile == NULL ) @@ -265,12 +279,6 @@ void Io_WriteAiger( Abc_Ntk_t * pNtk, char * pFileName, int fWriteSymbols, int f fprintf( stdout, "Io_WriteAiger(): Cannot open the output file \"%s\".\n", pFileName ); return; } - Abc_NtkForEachLatch( pNtk, pObj, i ) - if ( !Abc_LatchIsInit0(pObj) ) - { - fprintf( stdout, "Io_WriteAiger(): Cannot write AIGER format with non-0 latch init values. Run \"zero\".\n" ); - return; - } // set the node numbers to be used in the output file nNodes = 0; @@ -368,6 +376,246 @@ void Io_WriteAiger( Abc_Ntk_t * pNtk, char * pFileName, int fWriteSymbols, int f fclose( pFile ); } + +/**Function************************************************************* + + Synopsis [Procedure to write data into BZ2 file.] + + Description [Based on the vsnprintf() man page.] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +typedef struct bz2file { + FILE * f; + BZFILE * b; + char * buf; + int nBytes; + int nBytesMax; +} bz2file; + +int fprintfBz2Aig( bz2file * b, char * fmt, ... ) { + if (b->b) { + char * newBuf; + int bzError; + va_list ap; + while (1) { + va_start(ap,fmt); + b->nBytes = vsnprintf(b->buf,b->nBytesMax,fmt,ap); + va_end(ap); + if (b->nBytes > -1 && b->nBytes < b->nBytesMax) + break; + if (b->nBytes > -1) + b->nBytesMax = b->nBytes + 1; + else + b->nBytesMax *= 2; + if ((newBuf = REALLOC( char,b->buf,b->nBytesMax )) == NULL) + return -1; + else + b->buf = newBuf; + } + BZ2_bzWrite( &bzError, b->b, b->buf, b->nBytes ); + if (bzError == BZ_IO_ERROR) { + fprintf( stdout, "Ioa_WriteBlif(): I/O error writing to compressed stream.\n" ); + return -1; + } + return b->nBytes; + } else { + int n; + va_list ap; + va_start(ap,fmt); + n = vfprintf( b->f, fmt, ap); + va_end(ap); + return n; + } +} + +/**Function************************************************************* + + Synopsis [Writes the AIG in the binary AIGER format.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Io_WriteAiger( Abc_Ntk_t * pNtk, char * pFileName, int fWriteSymbols, int fCompact ) +{ + ProgressBar * pProgress; +// FILE * pFile; + Abc_Obj_t * pObj, * pDriver; + int i, nNodes, Pos, nBufferSize, bzError; + unsigned char * pBuffer; + unsigned uLit0, uLit1, uLit; + bz2file b; + + // check that the network is valid + assert( Abc_NtkIsStrash(pNtk) ); + Abc_NtkForEachLatch( pNtk, pObj, i ) + if ( !Abc_LatchIsInit0(pObj) ) + { + fprintf( stdout, "Io_WriteAiger(): Cannot write AIGER format with non-0 latch init values. Run \"zero\".\n" ); + return; + } + + memset(&b,0,sizeof(b)); + b.nBytesMax = (1<<12); + b.buf = ALLOC( char,b.nBytesMax ); + + // start the output stream + b.f = fopen( pFileName, "wb" ); + if ( b.f == NULL ) + { + fprintf( stdout, "Ioa_WriteBlif(): Cannot open the output file \"%s\".\n", pFileName ); + FREE(b.buf); + return; + } + if (!strncmp(pFileName+strlen(pFileName)-4,".bz2",4)) { + b.b = BZ2_bzWriteOpen( &bzError, b.f, 9, 0, 0 ); + if ( bzError != BZ_OK ) { + BZ2_bzWriteClose( &bzError, b.b, 0, NULL, NULL ); + fprintf( stdout, "Ioa_WriteBlif(): Cannot start compressed stream.\n" ); + fclose( b.f ); + FREE(b.buf); + return; + } + } + + // set the node numbers to be used in the output file + nNodes = 0; + Io_ObjSetAigerNum( Abc_AigConst1(pNtk), nNodes++ ); + Abc_NtkForEachCi( pNtk, pObj, i ) + Io_ObjSetAigerNum( pObj, nNodes++ ); + Abc_AigForEachAnd( pNtk, pObj, i ) + Io_ObjSetAigerNum( pObj, nNodes++ ); + + // write the header "M I L O A" where M = I + L + A + fprintfBz2Aig( &b, "aig%s %u %u %u %u %u\n", + fCompact? "2" : "", + Abc_NtkPiNum(pNtk) + Abc_NtkLatchNum(pNtk) + Abc_NtkNodeNum(pNtk), + Abc_NtkPiNum(pNtk), + Abc_NtkLatchNum(pNtk), + Abc_NtkPoNum(pNtk), + Abc_NtkNodeNum(pNtk) ); + + // if the driver node is a constant, we need to complement the literal below + // because, in the AIGER format, literal 0/1 is represented as number 0/1 + // while, in ABC, constant 1 node has number 0 and so literal 0/1 will be 1/0 + + if ( !fCompact ) + { + // write latch drivers + Abc_NtkForEachLatchInput( pNtk, pObj, i ) + { + pDriver = Abc_ObjFanin0(pObj); + fprintfBz2Aig( &b, "%u\n", Io_ObjMakeLit( Io_ObjAigerNum(pDriver), Abc_ObjFaninC0(pObj) ^ (Io_ObjAigerNum(pDriver) == 0) ) ); + } + // write PO drivers + Abc_NtkForEachPo( pNtk, pObj, i ) + { + pDriver = Abc_ObjFanin0(pObj); + fprintfBz2Aig( &b, "%u\n", Io_ObjMakeLit( Io_ObjAigerNum(pDriver), Abc_ObjFaninC0(pObj) ^ (Io_ObjAigerNum(pDriver) == 0) ) ); + } + } + else + { + Vec_Int_t * vLits = Io_WriteAigerLiterals( pNtk ); + Vec_Str_t * vBinary = Io_WriteEncodeLiterals( vLits ); + if ( !b.b ) + fwrite( Vec_StrArray(vBinary), 1, Vec_StrSize(vBinary), b.f ); + else + { + BZ2_bzWrite( &bzError, b.b, Vec_StrArray(vBinary), Vec_StrSize(vBinary) ); + if (bzError == BZ_IO_ERROR) { + fprintf( stdout, "Io_WriteAiger(): I/O error writing to compressed stream.\n" ); + fclose( b.f ); + FREE(b.buf); + return; + } + } + Vec_StrFree( vBinary ); + Vec_IntFree( vLits ); + } + + // write the nodes into the buffer + Pos = 0; + nBufferSize = 6 * Abc_NtkNodeNum(pNtk) + 100; // skeptically assuming 3 chars per one AIG edge + pBuffer = ALLOC( unsigned char, nBufferSize ); + pProgress = Extra_ProgressBarStart( stdout, Abc_NtkObjNumMax(pNtk) ); + Abc_AigForEachAnd( pNtk, pObj, i ) + { + Extra_ProgressBarUpdate( pProgress, i, NULL ); + uLit = Io_ObjMakeLit( Io_ObjAigerNum(pObj), 0 ); + uLit0 = Io_ObjMakeLit( Io_ObjAigerNum(Abc_ObjFanin0(pObj)), Abc_ObjFaninC0(pObj) ); + uLit1 = Io_ObjMakeLit( Io_ObjAigerNum(Abc_ObjFanin1(pObj)), Abc_ObjFaninC1(pObj) ); + assert( uLit0 < uLit1 ); + Pos = Io_WriteAigerEncode( pBuffer, Pos, (unsigned)(uLit - uLit1) ); + Pos = Io_WriteAigerEncode( pBuffer, Pos, (unsigned)(uLit1 - uLit0) ); + if ( Pos > nBufferSize - 10 ) + { + printf( "Io_WriteAiger(): AIGER generation has failed because the allocated buffer is too small.\n" ); + fclose( b.f ); + FREE(b.buf); + return; + } + } + assert( Pos < nBufferSize ); + Extra_ProgressBarStop( pProgress ); + + // write the buffer + if ( !b.b ) + fwrite( pBuffer, 1, Pos, b.f ); + else + { + BZ2_bzWrite( &bzError, b.b, pBuffer, Pos ); + if (bzError == BZ_IO_ERROR) { + fprintf( stdout, "Io_WriteAiger(): I/O error writing to compressed stream.\n" ); + fclose( b.f ); + FREE(b.buf); + return; + } + } + free( pBuffer ); + + // write the symbol table + if ( fWriteSymbols ) + { + // write PIs + Abc_NtkForEachPi( pNtk, pObj, i ) + fprintfBz2Aig( &b, "i%d %s\n", i, Abc_ObjName(pObj) ); + // write latches + Abc_NtkForEachLatch( pNtk, pObj, i ) + fprintfBz2Aig( &b, "l%d %s\n", i, Abc_ObjName(Abc_ObjFanout0(pObj)) ); + // write POs + Abc_NtkForEachPo( pNtk, pObj, i ) + fprintfBz2Aig( &b, "o%d %s\n", i, Abc_ObjName(pObj) ); + } + + // write the comment + fprintfBz2Aig( &b, "c\n" ); + if ( pNtk->pName && strlen(pNtk->pName) > 0 ) + fprintfBz2Aig( &b, ".model %s\n", pNtk->pName ); + fprintfBz2Aig( &b, "This file was produced by ABC on %s\n", Extra_TimeStamp() ); + fprintfBz2Aig( &b, "For information about AIGER format, refer to %s\n", "http://fmv.jku.at/aiger" ); + + // close the file + if (b.b) { + BZ2_bzWriteClose( &bzError, b.b, 0, NULL, NULL ); + if (bzError == BZ_IO_ERROR) { + fprintf( stdout, "Io_WriteAiger(): I/O error closing compressed stream.\n" ); + fclose( b.f ); + FREE(b.buf); + return; + } + } + fclose( b.f ); + FREE(b.buf); +} + //////////////////////////////////////////////////////////////////////// /// END OF FILE /// //////////////////////////////////////////////////////////////////////// diff --git a/src/misc/bzlib/CHANGES b/src/misc/bzlib/CHANGES new file mode 100644 index 00000000..6e4f65e2 --- /dev/null +++ b/src/misc/bzlib/CHANGES @@ -0,0 +1,319 @@ + ------------------------------------------------------------------ + This file is part of bzip2/libbzip2, a program and library for + lossless, block-sorting data compression. + + bzip2/libbzip2 version 1.0.5 of 10 December 2007 + Copyright (C) 1996-2007 Julian Seward <jseward@bzip.org> + + Please read the WARNING, DISCLAIMER and PATENTS sections in the + README file. + + This program is released under the terms of the license contained + in the file LICENSE. + ------------------------------------------------------------------ + + +0.9.0 +~~~~~ +First version. + + +0.9.0a +~~~~~~ +Removed 'ranlib' from Makefile, since most modern Unix-es +don't need it, or even know about it. + + +0.9.0b +~~~~~~ +Fixed a problem with error reporting in bzip2.c. This does not effect +the library in any way. Problem is: versions 0.9.0 and 0.9.0a (of the +program proper) compress and decompress correctly, but give misleading +error messages (internal panics) when an I/O error occurs, instead of +reporting the problem correctly. This shouldn't give any data loss +(as far as I can see), but is confusing. + +Made the inline declarations disappear for non-GCC compilers. + + +0.9.0c +~~~~~~ +Fixed some problems in the library pertaining to some boundary cases. +This makes the library behave more correctly in those situations. The +fixes apply only to features (calls and parameters) not used by +bzip2.c, so the non-fixedness of them in previous versions has no +effect on reliability of bzip2.c. + +In bzlib.c: + * made zero-length BZ_FLUSH work correctly in bzCompress(). + * fixed bzWrite/bzRead to ignore zero-length requests. + * fixed bzread to correctly handle read requests after EOF. + * wrong parameter order in call to bzDecompressInit in + bzBuffToBuffDecompress. Fixed. + +In compress.c: + * changed setting of nGroups in sendMTFValues() so as to + do a bit better on small files. This _does_ effect + bzip2.c. + + +0.9.5a +~~~~~~ +Major change: add a fallback sorting algorithm (blocksort.c) +to give reasonable behaviour even for very repetitive inputs. +Nuked --repetitive-best and --repetitive-fast since they are +no longer useful. + +Minor changes: mostly a whole bunch of small changes/ +bugfixes in the driver (bzip2.c). Changes pertaining to the +user interface are: + + allow decompression of symlink'd files to stdout + decompress/test files even without .bz2 extension + give more accurate error messages for I/O errors + when compressing/decompressing to stdout, don't catch control-C + read flags from BZIP2 and BZIP environment variables + decline to break hard links to a file unless forced with -f + allow -c flag even with no filenames + preserve file ownerships as far as possible + make -s -1 give the expected block size (100k) + add a flag -q --quiet to suppress nonessential warnings + stop decoding flags after --, so files beginning in - can be handled + resolved inconsistent naming: bzcat or bz2cat ? + bzip2 --help now returns 0 + +Programming-level changes are: + + fixed syntax error in GET_LL4 for Borland C++ 5.02 + let bzBuffToBuffDecompress return BZ_DATA_ERROR{_MAGIC} + fix overshoot of mode-string end in bzopen_or_bzdopen + wrapped bzlib.h in #ifdef __cplusplus ... extern "C" { ... } + close file handles under all error conditions + added minor mods so it compiles with DJGPP out of the box + fixed Makefile so it doesn't give problems with BSD make + fix uninitialised memory reads in dlltest.c + +0.9.5b +~~~~~~ +Open stdin/stdout in binary mode for DJGPP. + +0.9.5c +~~~~~~ +Changed BZ_N_OVERSHOOT to be ... + 2 instead of ... + 1. The + 1 +version could cause the sorted order to be wrong in some extremely +obscure cases. Also changed setting of quadrant in blocksort.c. + +0.9.5d +~~~~~~ +The only functional change is to make bzlibVersion() in the library +return the correct string. This has no effect whatsoever on the +functioning of the bzip2 program or library. Added a couple of casts +so the library compiles without warnings at level 3 in MS Visual +Studio 6.0. Included a Y2K statement in the file Y2K_INFO. All other +changes are minor documentation changes. + +1.0 +~~~ +Several minor bugfixes and enhancements: + +* Large file support. The library uses 64-bit counters to + count the volume of data passing through it. bzip2.c + is now compiled with -D_FILE_OFFSET_BITS=64 to get large + file support from the C library. -v correctly prints out + file sizes greater than 4 gigabytes. All these changes have + been made without assuming a 64-bit platform or a C compiler + which supports 64-bit ints, so, except for the C library + aspect, they are fully portable. + +* Decompression robustness. The library/program should be + robust to any corruption of compressed data, detecting and + handling _all_ corruption, instead of merely relying on + the CRCs. What this means is that the program should + never crash, given corrupted data, and the library should + always return BZ_DATA_ERROR. + +* Fixed an obscure race-condition bug only ever observed on + Solaris, in which, if you were very unlucky and issued + control-C at exactly the wrong time, both input and output + files would be deleted. + +* Don't run out of file handles on test/decompression when + large numbers of files have invalid magic numbers. + +* Avoid library namespace pollution. Prefix all exported + symbols with BZ2_. + +* Minor sorting enhancements from my DCC2000 paper. + +* Advance the version number to 1.0, so as to counteract the + (false-in-this-case) impression some people have that programs + with version numbers less than 1.0 are in some way, experimental, + pre-release versions. + +* Create an initial Makefile-libbz2_so to build a shared library. + Yes, I know I should really use libtool et al ... + +* Make the program exit with 2 instead of 0 when decompression + fails due to a bad magic number (ie, an invalid bzip2 header). + Also exit with 1 (as the manual claims :-) whenever a diagnostic + message would have been printed AND the corresponding operation + is aborted, for example + bzip2: Output file xx already exists. + When a diagnostic message is printed but the operation is not + aborted, for example + bzip2: Can't guess original name for wurble -- using wurble.out + then the exit value 0 is returned, unless some other problem is + also detected. + + I think it corresponds more closely to what the manual claims now. + + +1.0.1 +~~~~~ +* Modified dlltest.c so it uses the new BZ2_ naming scheme. +* Modified makefile-msc to fix minor build probs on Win2k. +* Updated README.COMPILATION.PROBLEMS. + +There are no functionality changes or bug fixes relative to version +1.0.0. This is just a documentation update + a fix for minor Win32 +build problems. For almost everyone, upgrading from 1.0.0 to 1.0.1 is +utterly pointless. Don't bother. + + +1.0.2 +~~~~~ +A bug fix release, addressing various minor issues which have appeared +in the 18 or so months since 1.0.1 was released. Most of the fixes +are to do with file-handling or documentation bugs. To the best of my +knowledge, there have been no data-loss-causing bugs reported in the +compression/decompression engine of 1.0.0 or 1.0.1. + +Note that this release does not improve the rather crude build system +for Unix platforms. The general plan here is to autoconfiscate/ +libtoolise 1.0.2 soon after release, and release the result as 1.1.0 +or perhaps 1.2.0. That, however, is still just a plan at this point. + +Here are the changes in 1.0.2. Bug-reporters and/or patch-senders in +parentheses. + +* Fix an infinite segfault loop in 1.0.1 when a directory is + encountered in -f (force) mode. + (Trond Eivind Glomsrod, Nicholas Nethercote, Volker Schmidt) + +* Avoid double fclose() of output file on certain I/O error paths. + (Solar Designer) + +* Don't fail with internal error 1007 when fed a long stream (> 48MB) + of byte 251. Also print useful message suggesting that 1007s may be + caused by bad memory. + (noticed by Juan Pedro Vallejo, fixed by me) + +* Fix uninitialised variable silly bug in demo prog dlltest.c. + (Jorj Bauer) + +* Remove 512-MB limitation on recovered file size for bzip2recover + on selected platforms which support 64-bit ints. At the moment + all GCC supported platforms, and Win32. + (me, Alson van der Meulen) + +* Hard-code header byte values, to give correct operation on platforms + using EBCDIC as their native character set (IBM's OS/390). + (Leland Lucius) + +* Copy file access times correctly. + (Marty Leisner) + +* Add distclean and check targets to Makefile. + (Michael Carmack) + +* Parameterise use of ar and ranlib in Makefile. Also add $(LDFLAGS). + (Rich Ireland, Bo Thorsen) + +* Pass -p (create parent dirs as needed) to mkdir during make install. + (Jeremy Fusco) + +* Dereference symlinks when copying file permissions in -f mode. + (Volker Schmidt) + +* Majorly simplify implementation of uInt64_qrm10. + (Bo Lindbergh) + +* Check the input file still exists before deleting the output one, + when aborting in cleanUpAndFail(). + (Joerg Prante, Robert Linden, Matthias Krings) + +Also a bunch of patches courtesy of Philippe Troin, the Debian maintainer +of bzip2: + +* Wrapper scripts (with manpages): bzdiff, bzgrep, bzmore. + +* Spelling changes and minor enhancements in bzip2.1. + +* Avoid race condition between creating the output file and setting its + interim permissions safely, by using fopen_output_safely(). + No changes to bzip2recover since there is no issue with file + permissions there. + +* do not print senseless report with -v when compressing an empty + file. + +* bzcat -f works on non-bzip2 files. + +* do not try to escape shell meta-characters on unix (the shell takes + care of these). + +* added --fast and --best aliases for -1 -9 for gzip compatibility. + + +1.0.3 (15 Feb 05) +~~~~~~~~~~~~~~~~~ +Fixes some minor bugs since the last version, 1.0.2. + +* Further robustification against corrupted compressed data. + There are currently no known bitstreams which can cause the + decompressor to crash, loop or access memory which does not + belong to it. If you are using bzip2 or the library to + decompress bitstreams from untrusted sources, an upgrade + to 1.0.3 is recommended. This fixes CAN-2005-1260. + +* The documentation has been converted to XML, from which html + and pdf can be derived. + +* Various minor bugs in the documentation have been fixed. + +* Fixes for various compilation warnings with newer versions of + gcc, and on 64-bit platforms. + +* The BZ_NO_STDIO cpp symbol was not properly observed in 1.0.2. + This has been fixed. + + +1.0.4 (20 Dec 06) +~~~~~~~~~~~~~~~~~ +Fixes some minor bugs since the last version, 1.0.3. + +* Fix file permissions race problem (CAN-2005-0953). + +* Avoid possible segfault in BZ2_bzclose. From Coverity's NetBSD + scan. + +* 'const'/prototype cleanups in the C code. + +* Change default install location to /usr/local, and handle multiple + 'make install's without error. + +* Sanitise file names more carefully in bzgrep. Fixes CAN-2005-0758 + to the extent that applies to bzgrep. + +* Use 'mktemp' rather than 'tempfile' in bzdiff. + +* Tighten up a couple of assertions in blocksort.c following automated + analysis. + +* Fix minor doc/comment bugs. + + +1.0.5 (10 Dec 07) +~~~~~~~~~~~~~~~~~ +Security fix only. Fixes CERT-FI 20469 as it applies to bzip2. + diff --git a/src/misc/bzlib/LICENSE b/src/misc/bzlib/LICENSE new file mode 100644 index 00000000..f420cffb --- /dev/null +++ b/src/misc/bzlib/LICENSE @@ -0,0 +1,42 @@ + +-------------------------------------------------------------------------- + +This program, "bzip2", the associated library "libbzip2", and all +documentation, are copyright (C) 1996-2007 Julian R Seward. All +rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +2. The origin of this software must not be misrepresented; you must + not claim that you wrote the original software. If you use this + software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + +3. Altered source versions must be plainly marked as such, and must + not be misrepresented as being the original software. + +4. The name of the author may not be used to endorse or promote + products derived from this software without specific prior written + permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS +OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE +GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +Julian Seward, jseward@bzip.org +bzip2/libbzip2 version 1.0.5 of 10 December 2007 + +-------------------------------------------------------------------------- diff --git a/src/misc/bzlib/blocksort.c b/src/misc/bzlib/blocksort.c new file mode 100644 index 00000000..95adb5ef --- /dev/null +++ b/src/misc/bzlib/blocksort.c @@ -0,0 +1,1094 @@ + +/*-------------------------------------------------------------*/ +/*--- Block sorting machinery ---*/ +/*--- blocksort.c ---*/ +/*-------------------------------------------------------------*/ + +/* ------------------------------------------------------------------ + This file is part of bzip2/libbzip2, a program and library for + lossless, block-sorting data compression. + + bzip2/libbzip2 version 1.0.5 of 10 December 2007 + Copyright (C) 1996-2007 Julian Seward <jseward@bzip.org> + + Please read the WARNING, DISCLAIMER and PATENTS sections in the + README file. + + This program is released under the terms of the license contained + in the file LICENSE. + ------------------------------------------------------------------ */ + + +#include "bzlib_private.h" + +/*---------------------------------------------*/ +/*--- Fallback O(N log(N)^2) sorting ---*/ +/*--- algorithm, for repetitive blocks ---*/ +/*---------------------------------------------*/ + +/*---------------------------------------------*/ +static +__inline__ +void fallbackSimpleSort ( UInt32* fmap, + UInt32* eclass, + Int32 lo, + Int32 hi ) +{ + Int32 i, j, tmp; + UInt32 ec_tmp; + + if (lo == hi) return; + + if (hi - lo > 3) { + for ( i = hi-4; i >= lo; i-- ) { + tmp = fmap[i]; + ec_tmp = eclass[tmp]; + for ( j = i+4; j <= hi && ec_tmp > eclass[fmap[j]]; j += 4 ) + fmap[j-4] = fmap[j]; + fmap[j-4] = tmp; + } + } + + for ( i = hi-1; i >= lo; i-- ) { + tmp = fmap[i]; + ec_tmp = eclass[tmp]; + for ( j = i+1; j <= hi && ec_tmp > eclass[fmap[j]]; j++ ) + fmap[j-1] = fmap[j]; + fmap[j-1] = tmp; + } +} + + +/*---------------------------------------------*/ +#define fswap(zz1, zz2) \ + { Int32 zztmp = zz1; zz1 = zz2; zz2 = zztmp; } + +#define fvswap(zzp1, zzp2, zzn) \ +{ \ + Int32 yyp1 = (zzp1); \ + Int32 yyp2 = (zzp2); \ + Int32 yyn = (zzn); \ + while (yyn > 0) { \ + fswap(fmap[yyp1], fmap[yyp2]); \ + yyp1++; yyp2++; yyn--; \ + } \ +} + + +#define fmin(a,b) ((a) < (b)) ? (a) : (b) + +#define fpush(lz,hz) { stackLo[sp] = lz; \ + stackHi[sp] = hz; \ + sp++; } + +#define fpop(lz,hz) { sp--; \ + lz = stackLo[sp]; \ + hz = stackHi[sp]; } + +#define FALLBACK_QSORT_SMALL_THRESH 10 +#define FALLBACK_QSORT_STACK_SIZE 100 + + +static +void fallbackQSort3 ( UInt32* fmap, + UInt32* eclass, + Int32 loSt, + Int32 hiSt ) +{ + Int32 unLo, unHi, ltLo, gtHi, n, m; + Int32 sp, lo, hi; + UInt32 med, r, r3; + Int32 stackLo[FALLBACK_QSORT_STACK_SIZE]; + Int32 stackHi[FALLBACK_QSORT_STACK_SIZE]; + + r = 0; + + sp = 0; + fpush ( loSt, hiSt ); + + while (sp > 0) { + + AssertH ( sp < FALLBACK_QSORT_STACK_SIZE - 1, 1004 ); + + fpop ( lo, hi ); + if (hi - lo < FALLBACK_QSORT_SMALL_THRESH) { + fallbackSimpleSort ( fmap, eclass, lo, hi ); + continue; + } + + /* Random partitioning. Median of 3 sometimes fails to + avoid bad cases. Median of 9 seems to help but + looks rather expensive. This too seems to work but + is cheaper. Guidance for the magic constants + 7621 and 32768 is taken from Sedgewick's algorithms + book, chapter 35. + */ + r = ((r * 7621) + 1) % 32768; + r3 = r % 3; + if (r3 == 0) med = eclass[fmap[lo]]; else + if (r3 == 1) med = eclass[fmap[(lo+hi)>>1]]; else + med = eclass[fmap[hi]]; + + unLo = ltLo = lo; + unHi = gtHi = hi; + + while (1) { + while (1) { + if (unLo > unHi) break; + n = (Int32)eclass[fmap[unLo]] - (Int32)med; + if (n == 0) { + fswap(fmap[unLo], fmap[ltLo]); + ltLo++; unLo++; + continue; + }; + if (n > 0) break; + unLo++; + } + while (1) { + if (unLo > unHi) break; + n = (Int32)eclass[fmap[unHi]] - (Int32)med; + if (n == 0) { + fswap(fmap[unHi], fmap[gtHi]); + gtHi--; unHi--; + continue; + }; + if (n < 0) break; + unHi--; + } + if (unLo > unHi) break; + fswap(fmap[unLo], fmap[unHi]); unLo++; unHi--; + } + + AssertD ( unHi == unLo-1, "fallbackQSort3(2)" ); + + if (gtHi < ltLo) continue; + + n = fmin(ltLo-lo, unLo-ltLo); fvswap(lo, unLo-n, n); + m = fmin(hi-gtHi, gtHi-unHi); fvswap(unLo, hi-m+1, m); + + n = lo + unLo - ltLo - 1; + m = hi - (gtHi - unHi) + 1; + + if (n - lo > hi - m) { + fpush ( lo, n ); + fpush ( m, hi ); + } else { + fpush ( m, hi ); + fpush ( lo, n ); + } + } +} + +#undef fmin +#undef fpush +#undef fpop +#undef fswap +#undef fvswap +#undef FALLBACK_QSORT_SMALL_THRESH +#undef FALLBACK_QSORT_STACK_SIZE + + +/*---------------------------------------------*/ +/* Pre: + nblock > 0 + eclass exists for [0 .. nblock-1] + ((UChar*)eclass) [0 .. nblock-1] holds block + ptr exists for [0 .. nblock-1] + + Post: + ((UChar*)eclass) [0 .. nblock-1] holds block + All other areas of eclass destroyed + fmap [0 .. nblock-1] holds sorted order + bhtab [ 0 .. 2+(nblock/32) ] destroyed +*/ + +#define SET_BH(zz) bhtab[(zz) >> 5] |= (1 << ((zz) & 31)) +#define CLEAR_BH(zz) bhtab[(zz) >> 5] &= ~(1 << ((zz) & 31)) +#define ISSET_BH(zz) (bhtab[(zz) >> 5] & (1 << ((zz) & 31))) +#define WORD_BH(zz) bhtab[(zz) >> 5] +#define UNALIGNED_BH(zz) ((zz) & 0x01f) + +static +void fallbackSort ( UInt32* fmap, + UInt32* eclass, + UInt32* bhtab, + Int32 nblock, + Int32 verb ) +{ + Int32 ftab[257]; + Int32 ftabCopy[256]; + Int32 H, i, j, k, l, r, cc, cc1; + Int32 nNotDone; + Int32 nBhtab; + UChar* eclass8 = (UChar*)eclass; + + /*-- + Initial 1-char radix sort to generate + initial fmap and initial BH bits. + --*/ + if (verb >= 4) + VPrintf0 ( " bucket sorting ...\n" ); + for (i = 0; i < 257; i++) ftab[i] = 0; + for (i = 0; i < nblock; i++) ftab[eclass8[i]]++; + for (i = 0; i < 256; i++) ftabCopy[i] = ftab[i]; + for (i = 1; i < 257; i++) ftab[i] += ftab[i-1]; + + for (i = 0; i < nblock; i++) { + j = eclass8[i]; + k = ftab[j] - 1; + ftab[j] = k; + fmap[k] = i; + } + + nBhtab = 2 + (nblock / 32); + for (i = 0; i < nBhtab; i++) bhtab[i] = 0; + for (i = 0; i < 256; i++) SET_BH(ftab[i]); + + /*-- + Inductively refine the buckets. Kind-of an + "exponential radix sort" (!), inspired by the + Manber-Myers suffix array construction algorithm. + --*/ + + /*-- set sentinel bits for block-end detection --*/ + for (i = 0; i < 32; i++) { + SET_BH(nblock + 2*i); + CLEAR_BH(nblock + 2*i + 1); + } + + /*-- the log(N) loop --*/ + H = 1; + while (1) { + + if (verb >= 4) + VPrintf1 ( " depth %6d has ", H ); + + j = 0; + for (i = 0; i < nblock; i++) { + if (ISSET_BH(i)) j = i; + k = fmap[i] - H; if (k < 0) k += nblock; + eclass[k] = j; + } + + nNotDone = 0; + r = -1; + while (1) { + + /*-- find the next non-singleton bucket --*/ + k = r + 1; + while (ISSET_BH(k) && UNALIGNED_BH(k)) k++; + if (ISSET_BH(k)) { + while (WORD_BH(k) == 0xffffffff) k += 32; + while (ISSET_BH(k)) k++; + } + l = k - 1; + if (l >= nblock) break; + while (!ISSET_BH(k) && UNALIGNED_BH(k)) k++; + if (!ISSET_BH(k)) { + while (WORD_BH(k) == 0x00000000) k += 32; + while (!ISSET_BH(k)) k++; + } + r = k - 1; + if (r >= nblock) break; + + /*-- now [l, r] bracket current bucket --*/ + if (r > l) { + nNotDone += (r - l + 1); + fallbackQSort3 ( fmap, eclass, l, r ); + + /*-- scan bucket and generate header bits-- */ + cc = -1; + for (i = l; i <= r; i++) { + cc1 = eclass[fmap[i]]; + if (cc != cc1) { SET_BH(i); cc = cc1; }; + } + } + } + + if (verb >= 4) + VPrintf1 ( "%6d unresolved strings\n", nNotDone ); + + H *= 2; + if (H > nblock || nNotDone == 0) break; + } + + /*-- + Reconstruct the original block in + eclass8 [0 .. nblock-1], since the + previous phase destroyed it. + --*/ + if (verb >= 4) + VPrintf0 ( " reconstructing block ...\n" ); + j = 0; + for (i = 0; i < nblock; i++) { + while (ftabCopy[j] == 0) j++; + ftabCopy[j]--; + eclass8[fmap[i]] = (UChar)j; + } + AssertH ( j < 256, 1005 ); +} + +#undef SET_BH +#undef CLEAR_BH +#undef ISSET_BH +#undef WORD_BH +#undef UNALIGNED_BH + + +/*---------------------------------------------*/ +/*--- The main, O(N^2 log(N)) sorting ---*/ +/*--- algorithm. Faster for "normal" ---*/ +/*--- non-repetitive blocks. ---*/ +/*---------------------------------------------*/ + +/*---------------------------------------------*/ +static +__inline__ +Bool mainGtU ( UInt32 i1, + UInt32 i2, + UChar* block, + UInt16* quadrant, + UInt32 nblock, + Int32* budget ) +{ + Int32 k; + UChar c1, c2; + UInt16 s1, s2; + + AssertD ( i1 != i2, "mainGtU" ); + /* 1 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + i1++; i2++; + /* 2 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + i1++; i2++; + /* 3 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + i1++; i2++; + /* 4 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + i1++; i2++; + /* 5 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + i1++; i2++; + /* 6 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + i1++; i2++; + /* 7 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + i1++; i2++; + /* 8 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + i1++; i2++; + /* 9 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + i1++; i2++; + /* 10 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + i1++; i2++; + /* 11 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + i1++; i2++; + /* 12 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + i1++; i2++; + + k = nblock + 8; + + do { + /* 1 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + s1 = quadrant[i1]; s2 = quadrant[i2]; + if (s1 != s2) return (s1 > s2); + i1++; i2++; + /* 2 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + s1 = quadrant[i1]; s2 = quadrant[i2]; + if (s1 != s2) return (s1 > s2); + i1++; i2++; + /* 3 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + s1 = quadrant[i1]; s2 = quadrant[i2]; + if (s1 != s2) return (s1 > s2); + i1++; i2++; + /* 4 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + s1 = quadrant[i1]; s2 = quadrant[i2]; + if (s1 != s2) return (s1 > s2); + i1++; i2++; + /* 5 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + s1 = quadrant[i1]; s2 = quadrant[i2]; + if (s1 != s2) return (s1 > s2); + i1++; i2++; + /* 6 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + s1 = quadrant[i1]; s2 = quadrant[i2]; + if (s1 != s2) return (s1 > s2); + i1++; i2++; + /* 7 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + s1 = quadrant[i1]; s2 = quadrant[i2]; + if (s1 != s2) return (s1 > s2); + i1++; i2++; + /* 8 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + s1 = quadrant[i1]; s2 = quadrant[i2]; + if (s1 != s2) return (s1 > s2); + i1++; i2++; + + if (i1 >= nblock) i1 -= nblock; + if (i2 >= nblock) i2 -= nblock; + + k -= 8; + (*budget)--; + } + while (k >= 0); + + return False; +} + + +/*---------------------------------------------*/ +/*-- + Knuth's increments seem to work better + than Incerpi-Sedgewick here. Possibly + because the number of elems to sort is + usually small, typically <= 20. +--*/ +static +Int32 incs[14] = { 1, 4, 13, 40, 121, 364, 1093, 3280, + 9841, 29524, 88573, 265720, + 797161, 2391484 }; + +static +void mainSimpleSort ( UInt32* ptr, + UChar* block, + UInt16* quadrant, + Int32 nblock, + Int32 lo, + Int32 hi, + Int32 d, + Int32* budget ) +{ + Int32 i, j, h, bigN, hp; + UInt32 v; + + bigN = hi - lo + 1; + if (bigN < 2) return; + + hp = 0; + while (incs[hp] < bigN) hp++; + hp--; + + for (; hp >= 0; hp--) { + h = incs[hp]; + + i = lo + h; + while (True) { + + /*-- copy 1 --*/ + if (i > hi) break; + v = ptr[i]; + j = i; + while ( mainGtU ( + ptr[j-h]+d, v+d, block, quadrant, nblock, budget + ) ) { + ptr[j] = ptr[j-h]; + j = j - h; + if (j <= (lo + h - 1)) break; + } + ptr[j] = v; + i++; + + /*-- copy 2 --*/ + if (i > hi) break; + v = ptr[i]; + j = i; + while ( mainGtU ( + ptr[j-h]+d, v+d, block, quadrant, nblock, budget + ) ) { + ptr[j] = ptr[j-h]; + j = j - h; + if (j <= (lo + h - 1)) break; + } + ptr[j] = v; + i++; + + /*-- copy 3 --*/ + if (i > hi) break; + v = ptr[i]; + j = i; + while ( mainGtU ( + ptr[j-h]+d, v+d, block, quadrant, nblock, budget + ) ) { + ptr[j] = ptr[j-h]; + j = j - h; + if (j <= (lo + h - 1)) break; + } + ptr[j] = v; + i++; + + if (*budget < 0) return; + } + } +} + + +/*---------------------------------------------*/ +/*-- + The following is an implementation of + an elegant 3-way quicksort for strings, + described in a paper "Fast Algorithms for + Sorting and Searching Strings", by Robert + Sedgewick and Jon L. Bentley. +--*/ + +#define mswap(zz1, zz2) \ + { Int32 zztmp = zz1; zz1 = zz2; zz2 = zztmp; } + +#define mvswap(zzp1, zzp2, zzn) \ +{ \ + Int32 yyp1 = (zzp1); \ + Int32 yyp2 = (zzp2); \ + Int32 yyn = (zzn); \ + while (yyn > 0) { \ + mswap(ptr[yyp1], ptr[yyp2]); \ + yyp1++; yyp2++; yyn--; \ + } \ +} + +static +__inline__ +UChar mmed3 ( UChar a, UChar b, UChar c ) +{ + UChar t; + if (a > b) { t = a; a = b; b = t; }; + if (b > c) { + b = c; + if (a > b) b = a; + } + return b; +} + +#define mmin(a,b) ((a) < (b)) ? (a) : (b) + +#define mpush(lz,hz,dz) { stackLo[sp] = lz; \ + stackHi[sp] = hz; \ + stackD [sp] = dz; \ + sp++; } + +#define mpop(lz,hz,dz) { sp--; \ + lz = stackLo[sp]; \ + hz = stackHi[sp]; \ + dz = stackD [sp]; } + + +#define mnextsize(az) (nextHi[az]-nextLo[az]) + +#define mnextswap(az,bz) \ + { Int32 tz; \ + tz = nextLo[az]; nextLo[az] = nextLo[bz]; nextLo[bz] = tz; \ + tz = nextHi[az]; nextHi[az] = nextHi[bz]; nextHi[bz] = tz; \ + tz = nextD [az]; nextD [az] = nextD [bz]; nextD [bz] = tz; } + + +#define MAIN_QSORT_SMALL_THRESH 20 +#define MAIN_QSORT_DEPTH_THRESH (BZ_N_RADIX + BZ_N_QSORT) +#define MAIN_QSORT_STACK_SIZE 100 + +static +void mainQSort3 ( UInt32* ptr, + UChar* block, + UInt16* quadrant, + Int32 nblock, + Int32 loSt, + Int32 hiSt, + Int32 dSt, + Int32* budget ) +{ + Int32 unLo, unHi, ltLo, gtHi, n, m, med; + Int32 sp, lo, hi, d; + + Int32 stackLo[MAIN_QSORT_STACK_SIZE]; + Int32 stackHi[MAIN_QSORT_STACK_SIZE]; + Int32 stackD [MAIN_QSORT_STACK_SIZE]; + + Int32 nextLo[3]; + Int32 nextHi[3]; + Int32 nextD [3]; + + sp = 0; + mpush ( loSt, hiSt, dSt ); + + while (sp > 0) { + + AssertH ( sp < MAIN_QSORT_STACK_SIZE - 2, 1001 ); + + mpop ( lo, hi, d ); + if (hi - lo < MAIN_QSORT_SMALL_THRESH || + d > MAIN_QSORT_DEPTH_THRESH) { + mainSimpleSort ( ptr, block, quadrant, nblock, lo, hi, d, budget ); + if (*budget < 0) return; + continue; + } + + med = (Int32) + mmed3 ( block[ptr[ lo ]+d], + block[ptr[ hi ]+d], + block[ptr[ (lo+hi)>>1 ]+d] ); + + unLo = ltLo = lo; + unHi = gtHi = hi; + + while (True) { + while (True) { + if (unLo > unHi) break; + n = ((Int32)block[ptr[unLo]+d]) - med; + if (n == 0) { + mswap(ptr[unLo], ptr[ltLo]); + ltLo++; unLo++; continue; + }; + if (n > 0) break; + unLo++; + } + while (True) { + if (unLo > unHi) break; + n = ((Int32)block[ptr[unHi]+d]) - med; + if (n == 0) { + mswap(ptr[unHi], ptr[gtHi]); + gtHi--; unHi--; continue; + }; + if (n < 0) break; + unHi--; + } + if (unLo > unHi) break; + mswap(ptr[unLo], ptr[unHi]); unLo++; unHi--; + } + + AssertD ( unHi == unLo-1, "mainQSort3(2)" ); + + if (gtHi < ltLo) { + mpush(lo, hi, d+1 ); + continue; + } + + n = mmin(ltLo-lo, unLo-ltLo); mvswap(lo, unLo-n, n); + m = mmin(hi-gtHi, gtHi-unHi); mvswap(unLo, hi-m+1, m); + + n = lo + unLo - ltLo - 1; + m = hi - (gtHi - unHi) + 1; + + nextLo[0] = lo; nextHi[0] = n; nextD[0] = d; + nextLo[1] = m; nextHi[1] = hi; nextD[1] = d; + nextLo[2] = n+1; nextHi[2] = m-1; nextD[2] = d+1; + + if (mnextsize(0) < mnextsize(1)) mnextswap(0,1); + if (mnextsize(1) < mnextsize(2)) mnextswap(1,2); + if (mnextsize(0) < mnextsize(1)) mnextswap(0,1); + + AssertD (mnextsize(0) >= mnextsize(1), "mainQSort3(8)" ); + AssertD (mnextsize(1) >= mnextsize(2), "mainQSort3(9)" ); + + mpush (nextLo[0], nextHi[0], nextD[0]); + mpush (nextLo[1], nextHi[1], nextD[1]); + mpush (nextLo[2], nextHi[2], nextD[2]); + } +} + +#undef mswap +#undef mvswap +#undef mpush +#undef mpop +#undef mmin +#undef mnextsize +#undef mnextswap +#undef MAIN_QSORT_SMALL_THRESH +#undef MAIN_QSORT_DEPTH_THRESH +#undef MAIN_QSORT_STACK_SIZE + + +/*---------------------------------------------*/ +/* Pre: + nblock > N_OVERSHOOT + block32 exists for [0 .. nblock-1 +N_OVERSHOOT] + ((UChar*)block32) [0 .. nblock-1] holds block + ptr exists for [0 .. nblock-1] + + Post: + ((UChar*)block32) [0 .. nblock-1] holds block + All other areas of block32 destroyed + ftab [0 .. 65536 ] destroyed + ptr [0 .. nblock-1] holds sorted order + if (*budget < 0), sorting was abandoned +*/ + +#define BIGFREQ(b) (ftab[((b)+1) << 8] - ftab[(b) << 8]) +#define SETMASK (1 << 21) +#define CLEARMASK (~(SETMASK)) + +static +void mainSort ( UInt32* ptr, + UChar* block, + UInt16* quadrant, + UInt32* ftab, + Int32 nblock, + Int32 verb, + Int32* budget ) +{ + Int32 i, j, k, ss, sb; + Int32 runningOrder[256]; + Bool bigDone[256]; + Int32 copyStart[256]; + Int32 copyEnd [256]; + UChar c1; + Int32 numQSorted; + UInt16 s; + if (verb >= 4) VPrintf0 ( " main sort initialise ...\n" ); + + /*-- set up the 2-byte frequency table --*/ + for (i = 65536; i >= 0; i--) ftab[i] = 0; + + j = block[0] << 8; + i = nblock-1; + for (; i >= 3; i -= 4) { + quadrant[i] = 0; + j = (j >> 8) | ( ((UInt16)block[i]) << 8); + ftab[j]++; + quadrant[i-1] = 0; + j = (j >> 8) | ( ((UInt16)block[i-1]) << 8); + ftab[j]++; + quadrant[i-2] = 0; + j = (j >> 8) | ( ((UInt16)block[i-2]) << 8); + ftab[j]++; + quadrant[i-3] = 0; + j = (j >> 8) | ( ((UInt16)block[i-3]) << 8); + ftab[j]++; + } + for (; i >= 0; i--) { + quadrant[i] = 0; + j = (j >> 8) | ( ((UInt16)block[i]) << 8); + ftab[j]++; + } + + /*-- (emphasises close relationship of block & quadrant) --*/ + for (i = 0; i < BZ_N_OVERSHOOT; i++) { + block [nblock+i] = block[i]; + quadrant[nblock+i] = 0; + } + + if (verb >= 4) VPrintf0 ( " bucket sorting ...\n" ); + + /*-- Complete the initial radix sort --*/ + for (i = 1; i <= 65536; i++) ftab[i] += ftab[i-1]; + + s = block[0] << 8; + i = nblock-1; + for (; i >= 3; i -= 4) { + s = (s >> 8) | (block[i] << 8); + j = ftab[s] -1; + ftab[s] = j; + ptr[j] = i; + s = (s >> 8) | (block[i-1] << 8); + j = ftab[s] -1; + ftab[s] = j; + ptr[j] = i-1; + s = (s >> 8) | (block[i-2] << 8); + j = ftab[s] -1; + ftab[s] = j; + ptr[j] = i-2; + s = (s >> 8) | (block[i-3] << 8); + j = ftab[s] -1; + ftab[s] = j; + ptr[j] = i-3; + } + for (; i >= 0; i--) { + s = (s >> 8) | (block[i] << 8); + j = ftab[s] -1; + ftab[s] = j; + ptr[j] = i; + } + + /*-- + Now ftab contains the first loc of every small bucket. + Calculate the running order, from smallest to largest + big bucket. + --*/ + for (i = 0; i <= 255; i++) { + bigDone [i] = False; + runningOrder[i] = i; + } + + { + Int32 vv; + Int32 h = 1; + do h = 3 * h + 1; while (h <= 256); + do { + h = h / 3; + for (i = h; i <= 255; i++) { + vv = runningOrder[i]; + j = i; + while ( BIGFREQ(runningOrder[j-h]) > BIGFREQ(vv) ) { + runningOrder[j] = runningOrder[j-h]; + j = j - h; + if (j <= (h - 1)) goto zero; + } + zero: + runningOrder[j] = vv; + } + } while (h != 1); + } + + /*-- + The main sorting loop. + --*/ + + numQSorted = 0; + + for (i = 0; i <= 255; i++) { + + /*-- + Process big buckets, starting with the least full. + Basically this is a 3-step process in which we call + mainQSort3 to sort the small buckets [ss, j], but + also make a big effort to avoid the calls if we can. + --*/ + ss = runningOrder[i]; + + /*-- + Step 1: + Complete the big bucket [ss] by quicksorting + any unsorted small buckets [ss, j], for j != ss. + Hopefully previous pointer-scanning phases have already + completed many of the small buckets [ss, j], so + we don't have to sort them at all. + --*/ + for (j = 0; j <= 255; j++) { + if (j != ss) { + sb = (ss << 8) + j; + if ( ! (ftab[sb] & SETMASK) ) { + Int32 lo = ftab[sb] & CLEARMASK; + Int32 hi = (ftab[sb+1] & CLEARMASK) - 1; + if (hi > lo) { + if (verb >= 4) + VPrintf4 ( " qsort [0x%x, 0x%x] " + "done %d this %d\n", + ss, j, numQSorted, hi - lo + 1 ); + mainQSort3 ( + ptr, block, quadrant, nblock, + lo, hi, BZ_N_RADIX, budget + ); + numQSorted += (hi - lo + 1); + if (*budget < 0) return; + } + } + ftab[sb] |= SETMASK; + } + } + + AssertH ( !bigDone[ss], 1006 ); + + /*-- + Step 2: + Now scan this big bucket [ss] so as to synthesise the + sorted order for small buckets [t, ss] for all t, + including, magically, the bucket [ss,ss] too. + This will avoid doing Real Work in subsequent Step 1's. + --*/ + { + for (j = 0; j <= 255; j++) { + copyStart[j] = ftab[(j << 8) + ss] & CLEARMASK; + copyEnd [j] = (ftab[(j << 8) + ss + 1] & CLEARMASK) - 1; + } + for (j = ftab[ss << 8] & CLEARMASK; j < copyStart[ss]; j++) { + k = ptr[j]-1; if (k < 0) k += nblock; + c1 = block[k]; + if (!bigDone[c1]) + ptr[ copyStart[c1]++ ] = k; + } + for (j = (ftab[(ss+1) << 8] & CLEARMASK) - 1; j > copyEnd[ss]; j--) { + k = ptr[j]-1; if (k < 0) k += nblock; + c1 = block[k]; + if (!bigDone[c1]) + ptr[ copyEnd[c1]-- ] = k; + } + } + + AssertH ( (copyStart[ss]-1 == copyEnd[ss]) + || + /* Extremely rare case missing in bzip2-1.0.0 and 1.0.1. + Necessity for this case is demonstrated by compressing + a sequence of approximately 48.5 million of character + 251; 1.0.0/1.0.1 will then die here. */ + (copyStart[ss] == 0 && copyEnd[ss] == nblock-1), + 1007 ) + + for (j = 0; j <= 255; j++) ftab[(j << 8) + ss] |= SETMASK; + + /*-- + Step 3: + The [ss] big bucket is now done. Record this fact, + and update the quadrant descriptors. Remember to + update quadrants in the overshoot area too, if + necessary. The "if (i < 255)" test merely skips + this updating for the last bucket processed, since + updating for the last bucket is pointless. + + The quadrant array provides a way to incrementally + cache sort orderings, as they appear, so as to + make subsequent comparisons in fullGtU() complete + faster. For repetitive blocks this makes a big + difference (but not big enough to be able to avoid + the fallback sorting mechanism, exponential radix sort). + + The precise meaning is: at all times: + + for 0 <= i < nblock and 0 <= j <= nblock + + if block[i] != block[j], + + then the relative values of quadrant[i] and + quadrant[j] are meaningless. + + else { + if quadrant[i] < quadrant[j] + then the string starting at i lexicographically + precedes the string starting at j + + else if quadrant[i] > quadrant[j] + then the string starting at j lexicographically + precedes the string starting at i + + else + the relative ordering of the strings starting + at i and j has not yet been determined. + } + --*/ + bigDone[ss] = True; + + if (i < 255) { + Int32 bbStart = ftab[ss << 8] & CLEARMASK; + Int32 bbSize = (ftab[(ss+1) << 8] & CLEARMASK) - bbStart; + Int32 shifts = 0; + + while ((bbSize >> shifts) > 65534) shifts++; + + for (j = bbSize-1; j >= 0; j--) { + Int32 a2update = ptr[bbStart + j]; + UInt16 qVal = (UInt16)(j >> shifts); + quadrant[a2update] = qVal; + if (a2update < BZ_N_OVERSHOOT) + quadrant[a2update + nblock] = qVal; + } + AssertH ( ((bbSize-1) >> shifts) <= 65535, 1002 ); + } + + } + + if (verb >= 4) + VPrintf3 ( " %d pointers, %d sorted, %d scanned\n", + nblock, numQSorted, nblock - numQSorted ); +} + +#undef BIGFREQ +#undef SETMASK +#undef CLEARMASK + + +/*---------------------------------------------*/ +/* Pre: + nblock > 0 + arr2 exists for [0 .. nblock-1 +N_OVERSHOOT] + ((UChar*)arr2) [0 .. nblock-1] holds block + arr1 exists for [0 .. nblock-1] + + Post: + ((UChar*)arr2) [0 .. nblock-1] holds block + All other areas of block destroyed + ftab [ 0 .. 65536 ] destroyed + arr1 [0 .. nblock-1] holds sorted order +*/ +void BZ2_blockSort ( EState* s ) +{ + UInt32* ptr = s->ptr; + UChar* block = s->block; + UInt32* ftab = s->ftab; + Int32 nblock = s->nblock; + Int32 verb = s->verbosity; + Int32 wfact = s->workFactor; + UInt16* quadrant; + Int32 budget; + Int32 budgetInit; + Int32 i; + + if (nblock < 10000) { + fallbackSort ( s->arr1, s->arr2, ftab, nblock, verb ); + } else { + /* Calculate the location for quadrant, remembering to get + the alignment right. Assumes that &(block[0]) is at least + 2-byte aligned -- this should be ok since block is really + the first section of arr2. + */ + i = nblock+BZ_N_OVERSHOOT; + if (i & 1) i++; + quadrant = (UInt16*)(&(block[i])); + + /* (wfact-1) / 3 puts the default-factor-30 + transition point at very roughly the same place as + with v0.1 and v0.9.0. + Not that it particularly matters any more, since the + resulting compressed stream is now the same regardless + of whether or not we use the main sort or fallback sort. + */ + if (wfact < 1 ) wfact = 1; + if (wfact > 100) wfact = 100; + budgetInit = nblock * ((wfact-1) / 3); + budget = budgetInit; + + mainSort ( ptr, block, quadrant, ftab, nblock, verb, &budget ); + if (verb >= 3) + VPrintf3 ( " %d work, %d block, ratio %5.2f\n", + budgetInit - budget, + nblock, + (float)(budgetInit - budget) / + (float)(nblock==0 ? 1 : nblock) ); + if (budget < 0) { + if (verb >= 2) + VPrintf0 ( " too repetitive; using fallback" + " sorting algorithm\n" ); + fallbackSort ( s->arr1, s->arr2, ftab, nblock, verb ); + } + } + + s->origPtr = -1; + for (i = 0; i < s->nblock; i++) + if (ptr[i] == 0) + { s->origPtr = i; break; }; + + AssertH( s->origPtr != -1, 1003 ); +} + + +/*-------------------------------------------------------------*/ +/*--- end blocksort.c ---*/ +/*-------------------------------------------------------------*/ diff --git a/src/misc/bzlib/bzip2.txt b/src/misc/bzlib/bzip2.txt new file mode 100644 index 00000000..4fb9c743 --- /dev/null +++ b/src/misc/bzlib/bzip2.txt @@ -0,0 +1,391 @@ + +NAME + bzip2, bunzip2 - a block-sorting file compressor, v1.0.4 + bzcat - decompresses files to stdout + bzip2recover - recovers data from damaged bzip2 files + + +SYNOPSIS + bzip2 [ -cdfkqstvzVL123456789 ] [ filenames ... ] + bunzip2 [ -fkvsVL ] [ filenames ... ] + bzcat [ -s ] [ filenames ... ] + bzip2recover filename + + +DESCRIPTION + bzip2 compresses files using the Burrows-Wheeler block + sorting text compression algorithm, and Huffman coding. + Compression is generally considerably better than that + achieved by more conventional LZ77/LZ78-based compressors, + and approaches the performance of the PPM family of sta- + tistical compressors. + + The command-line options are deliberately very similar to + those of GNU gzip, but they are not identical. + + bzip2 expects a list of file names to accompany the com- + mand-line flags. Each file is replaced by a compressed + version of itself, with the name "original_name.bz2". + Each compressed file has the same modification date, per- + missions, and, when possible, ownership as the correspond- + ing original, so that these properties can be correctly + restored at decompression time. File name handling is + naive in the sense that there is no mechanism for preserv- + ing original file names, permissions, ownerships or dates + in filesystems which lack these concepts, or have serious + file name length restrictions, such as MS-DOS. + + bzip2 and bunzip2 will by default not overwrite existing + files. If you want this to happen, specify the -f flag. + + If no file names are specified, bzip2 compresses from + standard input to standard output. In this case, bzip2 + will decline to write compressed output to a terminal, as + this would be entirely incomprehensible and therefore + pointless. + + bunzip2 (or bzip2 -d) decompresses all specified files. + Files which were not created by bzip2 will be detected and + ignored, and a warning issued. bzip2 attempts to guess + the filename for the decompressed file from that of the + compressed file as follows: + + filename.bz2 becomes filename + filename.bz becomes filename + filename.tbz2 becomes filename.tar + filename.tbz becomes filename.tar + anyothername becomes anyothername.out + + If the file does not end in one of the recognised endings, + .bz2, .bz, .tbz2 or .tbz, bzip2 complains that it cannot + guess the name of the original file, and uses the original + name with .out appended. + + As with compression, supplying no filenames causes decom- + pression from standard input to standard output. + + bunzip2 will correctly decompress a file which is the con- + catenation of two or more compressed files. The result is + the concatenation of the corresponding uncompressed files. + Integrity testing (-t) of concatenated compressed files is + also supported. + + You can also compress or decompress files to the standard + output by giving the -c flag. Multiple files may be com- + pressed and decompressed like this. The resulting outputs + are fed sequentially to stdout. Compression of multiple + files in this manner generates a stream containing multi- + ple compressed file representations. Such a stream can be + decompressed correctly only by bzip2 version 0.9.0 or + later. Earlier versions of bzip2 will stop after decom- + pressing the first file in the stream. + + bzcat (or bzip2 -dc) decompresses all specified files to + the standard output. + + bzip2 will read arguments from the environment variables + BZIP2 and BZIP, in that order, and will process them + before any arguments read from the command line. This + gives a convenient way to supply default arguments. + + Compression is always performed, even if the compressed + file is slightly larger than the original. Files of less + than about one hundred bytes tend to get larger, since the + compression mechanism has a constant overhead in the + region of 50 bytes. Random data (including the output of + most file compressors) is coded at about 8.05 bits per + byte, giving an expansion of around 0.5%. + + As a self-check for your protection, bzip2 uses 32-bit + CRCs to make sure that the decompressed version of a file + is identical to the original. This guards against corrup- + tion of the compressed data, and against undetected bugs + in bzip2 (hopefully very unlikely). The chances of data + corruption going undetected is microscopic, about one + chance in four billion for each file processed. Be aware, + though, that the check occurs upon decompression, so it + can only tell you that something is wrong. It can't help + you recover the original uncompressed data. You can use + bzip2recover to try to recover data from damaged files. + + Return values: 0 for a normal exit, 1 for environmental + problems (file not found, invalid flags, I/O errors, &c), + 2 to indicate a corrupt compressed file, 3 for an internal + consistency error (eg, bug) which caused bzip2 to panic. + + +OPTIONS + -c --stdout + Compress or decompress to standard output. + + -d --decompress + Force decompression. bzip2, bunzip2 and bzcat are + really the same program, and the decision about + what actions to take is done on the basis of which + name is used. This flag overrides that mechanism, + and forces bzip2 to decompress. + + -z --compress + The complement to -d: forces compression, + regardless of the invocation name. + + -t --test + Check integrity of the specified file(s), but don't + decompress them. This really performs a trial + decompression and throws away the result. + + -f --force + Force overwrite of output files. Normally, bzip2 + will not overwrite existing output files. Also + forces bzip2 to break hard links to files, which it + otherwise wouldn't do. + + bzip2 normally declines to decompress files which + don't have the correct magic header bytes. If + forced (-f), however, it will pass such files + through unmodified. This is how GNU gzip behaves. + + -k --keep + Keep (don't delete) input files during compression + or decompression. + + -s --small + Reduce memory usage, for compression, decompression + and testing. Files are decompressed and tested + using a modified algorithm which only requires 2.5 + bytes per block byte. This means any file can be + decompressed in 2300k of memory, albeit at about + half the normal speed. + + During compression, -s selects a block size of + 200k, which limits memory use to around the same + figure, at the expense of your compression ratio. + In short, if your machine is low on memory (8 + megabytes or less), use -s for everything. See + MEMORY MANAGEMENT below. + + -q --quiet + Suppress non-essential warning messages. Messages + pertaining to I/O errors and other critical events + will not be suppressed. + + -v --verbose + Verbose mode -- show the compression ratio for each + file processed. Further -v's increase the ver- + bosity level, spewing out lots of information which + is primarily of interest for diagnostic purposes. + + -L --license -V --version + Display the software version, license terms and + conditions. + + -1 (or --fast) to -9 (or --best) + Set the block size to 100 k, 200 k .. 900 k when + compressing. Has no effect when decompressing. + See MEMORY MANAGEMENT below. The --fast and --best + aliases are primarily for GNU gzip compatibility. + In particular, --fast doesn't make things signifi- + cantly faster. And --best merely selects the + default behaviour. + + -- Treats all subsequent arguments as file names, even + if they start with a dash. This is so you can han- + dle files with names beginning with a dash, for + example: bzip2 -- -myfilename. + + --repetitive-fast --repetitive-best + These flags are redundant in versions 0.9.5 and + above. They provided some coarse control over the + behaviour of the sorting algorithm in earlier ver- + sions, which was sometimes useful. 0.9.5 and above + have an improved algorithm which renders these + flags irrelevant. + + +MEMORY MANAGEMENT + bzip2 compresses large files in blocks. The block size + affects both the compression ratio achieved, and the + amount of memory needed for compression and decompression. + The flags -1 through -9 specify the block size to be + 100,000 bytes through 900,000 bytes (the default) respec- + tively. At decompression time, the block size used for + compression is read from the header of the compressed + file, and bunzip2 then allocates itself just enough memory + to decompress the file. Since block sizes are stored in + compressed files, it follows that the flags -1 to -9 are + irrelevant to and so ignored during decompression. + + Compression and decompression requirements, in bytes, can + be estimated as: + + Compression: 400k + ( 8 x block size ) + + Decompression: 100k + ( 4 x block size ), or + 100k + ( 2.5 x block size ) + + Larger block sizes give rapidly diminishing marginal + returns. Most of the compression comes from the first two + or three hundred k of block size, a fact worth bearing in + mind when using bzip2 on small machines. It is also + important to appreciate that the decompression memory + requirement is set at compression time by the choice of + block size. + + For files compressed with the default 900k block size, + bunzip2 will require about 3700 kbytes to decompress. To + support decompression of any file on a 4 megabyte machine, + bunzip2 has an option to decompress using approximately + half this amount of memory, about 2300 kbytes. Decompres- + sion speed is also halved, so you should use this option + only where necessary. The relevant flag is -s. + + In general, try and use the largest block size memory con- + straints allow, since that maximises the compression + achieved. Compression and decompression speed are virtu- + ally unaffected by block size. + + Another significant point applies to files which fit in a + single block -- that means most files you'd encounter + using a large block size. The amount of real memory + touched is proportional to the size of the file, since the + file is smaller than a block. For example, compressing a + file 20,000 bytes long with the flag -9 will cause the + compressor to allocate around 7600k of memory, but only + touch 400k + 20000 * 8 = 560 kbytes of it. Similarly, the + decompressor will allocate 3700k but only touch 100k + + 20000 * 4 = 180 kbytes. + + Here is a table which summarises the maximum memory usage + for different block sizes. Also recorded is the total + compressed size for 14 files of the Calgary Text Compres- + sion Corpus totalling 3,141,622 bytes. This column gives + some feel for how compression varies with block size. + These figures tend to understate the advantage of larger + block sizes for larger files, since the Corpus is domi- + nated by smaller files. + + Compress Decompress Decompress Corpus + Flag usage usage -s usage Size + + -1 1200k 500k 350k 914704 + -2 2000k 900k 600k 877703 + -3 2800k 1300k 850k 860338 + -4 3600k 1700k 1100k 846899 + -5 4400k 2100k 1350k 845160 + -6 5200k 2500k 1600k 838626 + -7 6100k 2900k 1850k 834096 + -8 6800k 3300k 2100k 828642 + -9 7600k 3700k 2350k 828642 + + +RECOVERING DATA FROM DAMAGED FILES + bzip2 compresses files in blocks, usually 900kbytes long. + Each block is handled independently. If a media or trans- + mission error causes a multi-block .bz2 file to become + damaged, it may be possible to recover data from the + undamaged blocks in the file. + + The compressed representation of each block is delimited + by a 48-bit pattern, which makes it possible to find the + block boundaries with reasonable certainty. Each block + also carries its own 32-bit CRC, so damaged blocks can be + distinguished from undamaged ones. + + bzip2recover is a simple program whose purpose is to + search for blocks in .bz2 files, and write each block out + into its own .bz2 file. You can then use bzip2 -t to test + the integrity of the resulting files, and decompress those + which are undamaged. + + bzip2recover takes a single argument, the name of the dam- + aged file, and writes a number of files + "rec00001file.bz2", "rec00002file.bz2", etc, containing + the extracted blocks. The output filenames are + designed so that the use of wildcards in subsequent pro- + cessing -- for example, "bzip2 -dc rec*file.bz2 > recov- + ered_data" -- processes the files in the correct order. + + bzip2recover should be of most use dealing with large .bz2 + files, as these will contain many blocks. It is clearly + futile to use it on damaged single-block files, since a + damaged block cannot be recovered. If you wish to min- + imise any potential data loss through media or transmis- + sion errors, you might consider compressing with a smaller + block size. + + +PERFORMANCE NOTES + The sorting phase of compression gathers together similar + strings in the file. Because of this, files containing + very long runs of repeated symbols, like "aabaabaabaab + ..." (repeated several hundred times) may compress more + slowly than normal. Versions 0.9.5 and above fare much + better than previous versions in this respect. The ratio + between worst-case and average-case compression time is in + the region of 10:1. For previous versions, this figure + was more like 100:1. You can use the -vvvv option to mon- + itor progress in great detail, if you want. + + Decompression speed is unaffected by these phenomena. + + bzip2 usually allocates several megabytes of memory to + operate in, and then charges all over it in a fairly ran- + dom fashion. This means that performance, both for com- + pressing and decompressing, is largely determined by the + speed at which your machine can service cache misses. + Because of this, small changes to the code to reduce the + miss rate have been observed to give disproportionately + large performance improvements. I imagine bzip2 will per- + form best on machines with very large caches. + + +CAVEATS + I/O error messages are not as helpful as they could be. + bzip2 tries hard to detect I/O errors and exit cleanly, + but the details of what the problem is sometimes seem + rather misleading. + + This manual page pertains to version 1.0.4 of bzip2. Com- + pressed data created by this version is entirely forwards + and backwards compatible with the previous public + releases, versions 0.1pl2, 0.9.0, 0.9.5, 1.0.0, 1.0.1, + 1.0.2 and 1.0.3, but with the following exception: 0.9.0 + and above can correctly decompress multiple concatenated + compressed files. 0.1pl2 cannot do this; it will stop + after decompressing just the first file in the stream. + + bzip2recover versions prior to 1.0.2 used 32-bit integers + to represent bit positions in compressed files, so they + could not handle compressed files more than 512 megabytes + long. Versions 1.0.2 and above use 64-bit ints on some + platforms which support them (GNU supported targets, and + Windows). To establish whether or not bzip2recover was + built with such a limitation, run it without arguments. + In any event you can build yourself an unlimited version + if you can recompile it with MaybeUInt64 set to be an + unsigned 64-bit integer. + + +AUTHOR + Julian Seward, jsewardbzip.org. + + http://www.bzip.org + + The ideas embodied in bzip2 are due to (at least) the fol- + lowing people: Michael Burrows and David Wheeler (for the + block sorting transformation), David Wheeler (again, for + the Huffman coder), Peter Fenwick (for the structured cod- + ing model in the original bzip, and many refinements), and + Alistair Moffat, Radford Neal and Ian Witten (for the + arithmetic coder in the original bzip). I am much + indebted for their help, support and advice. See the man- + ual in the source distribution for pointers to sources of + documentation. Christian von Roques encouraged me to look + for faster sorting algorithms, so as to speed up compres- + sion. Bela Lubkin encouraged me to improve the worst-case + compression performance. Donna Robinson XMLised the docu- + mentation. The bz* scripts are derived from those of GNU + gzip. Many people sent patches, helped with portability + problems, lent machines, gave advice and were generally + helpful. + diff --git a/src/misc/bzlib/bzlib.c b/src/misc/bzlib/bzlib.c new file mode 100644 index 00000000..9d040682 --- /dev/null +++ b/src/misc/bzlib/bzlib.c @@ -0,0 +1,1571 @@ + +/*-------------------------------------------------------------*/ +/*--- Library top-level functions. ---*/ +/*--- bzlib.c ---*/ +/*-------------------------------------------------------------*/ + +/* ------------------------------------------------------------------ + This file is part of bzip2/libbzip2, a program and library for + lossless, block-sorting data compression. + + bzip2/libbzip2 version 1.0.5 of 10 December 2007 + Copyright (C) 1996-2007 Julian Seward <jseward@bzip.org> + + Please read the WARNING, DISCLAIMER and PATENTS sections in the + README file. + + This program is released under the terms of the license contained + in the file LICENSE. + ------------------------------------------------------------------ */ + +/* CHANGES + 0.9.0 -- original version. + 0.9.0a/b -- no changes in this file. + 0.9.0c -- made zero-length BZ_FLUSH work correctly in bzCompress(). + fixed bzWrite/bzRead to ignore zero-length requests. + fixed bzread to correctly handle read requests after EOF. + wrong parameter order in call to bzDecompressInit in + bzBuffToBuffDecompress. Fixed. +*/ + +#include "bzlib_private.h" + +/*---------------------------------------------------*/ +/*--- Compression stuff ---*/ +/*---------------------------------------------------*/ + + +/*---------------------------------------------------*/ +#ifndef BZ_NO_STDIO +void BZ2_bz__AssertH__fail ( int errcode ) +{ + fprintf(stderr, + "\n\nbzip2/libbzip2: internal error number %d.\n" + "This is a bug in bzip2/libbzip2, %s.\n" + "Please report it to me at: jseward@bzip.org. If this happened\n" + "when you were using some program which uses libbzip2 as a\n" + "component, you should also report this bug to the author(s)\n" + "of that program. Please make an effort to report this bug;\n" + "timely and accurate bug reports eventually lead to higher\n" + "quality software. Thanks. Julian Seward, 10 December 2007.\n\n", + errcode, + BZ2_bzlibVersion() + ); + + if (errcode == 1007) { + fprintf(stderr, + "\n*** A special note about internal error number 1007 ***\n" + "\n" + "Experience suggests that a common cause of i.e. 1007\n" + "is unreliable memory or other hardware. The 1007 assertion\n" + "just happens to cross-check the results of huge numbers of\n" + "memory reads/writes, and so acts (unintendedly) as a stress\n" + "test of your memory system.\n" + "\n" + "I suggest the following: try compressing the file again,\n" + "possibly monitoring progress in detail with the -vv flag.\n" + "\n" + "* If the error cannot be reproduced, and/or happens at different\n" + " points in compression, you may have a flaky memory system.\n" + " Try a memory-test program. I have used Memtest86\n" + " (www.memtest86.com). At the time of writing it is free (GPLd).\n" + " Memtest86 tests memory much more thorougly than your BIOSs\n" + " power-on test, and may find failures that the BIOS doesn't.\n" + "\n" + "* If the error can be repeatably reproduced, this is a bug in\n" + " bzip2, and I would very much like to hear about it. Please\n" + " let me know, and, ideally, save a copy of the file causing the\n" + " problem -- without which I will be unable to investigate it.\n" + "\n" + ); + } + + exit(3); +} +#endif + + +/*---------------------------------------------------*/ +static +int bz_config_ok ( void ) +{ + if (sizeof(int) != 4) return 0; + if (sizeof(short) != 2) return 0; + if (sizeof(char) != 1) return 0; + return 1; +} + + +/*---------------------------------------------------*/ +static +void* default_bzalloc ( void* opaque, Int32 items, Int32 size ) +{ + void* v = malloc ( items * size ); + return v; +} + +static +void default_bzfree ( void* opaque, void* addr ) +{ + if (addr != NULL) free ( addr ); +} + + +/*---------------------------------------------------*/ +static +void prepare_new_block ( EState* s ) +{ + Int32 i; + s->nblock = 0; + s->numZ = 0; + s->state_out_pos = 0; + BZ_INITIALISE_CRC ( s->blockCRC ); + for (i = 0; i < 256; i++) s->inUse[i] = False; + s->blockNo++; +} + + +/*---------------------------------------------------*/ +static +void init_RL ( EState* s ) +{ + s->state_in_ch = 256; + s->state_in_len = 0; +} + + +static +Bool isempty_RL ( EState* s ) +{ + if (s->state_in_ch < 256 && s->state_in_len > 0) + return False; else + return True; +} + + +/*---------------------------------------------------*/ +int BZ_API(BZ2_bzCompressInit) + ( bz_stream* strm, + int blockSize100k, + int verbosity, + int workFactor ) +{ + Int32 n; + EState* s; + + if (!bz_config_ok()) return BZ_CONFIG_ERROR; + + if (strm == NULL || + blockSize100k < 1 || blockSize100k > 9 || + workFactor < 0 || workFactor > 250) + return BZ_PARAM_ERROR; + + if (workFactor == 0) workFactor = 30; + if (strm->bzalloc == NULL) strm->bzalloc = default_bzalloc; + if (strm->bzfree == NULL) strm->bzfree = default_bzfree; + + s = BZALLOC( sizeof(EState) ); + if (s == NULL) return BZ_MEM_ERROR; + s->strm = strm; + + s->arr1 = NULL; + s->arr2 = NULL; + s->ftab = NULL; + + n = 100000 * blockSize100k; + s->arr1 = BZALLOC( n * sizeof(UInt32) ); + s->arr2 = BZALLOC( (n+BZ_N_OVERSHOOT) * sizeof(UInt32) ); + s->ftab = BZALLOC( 65537 * sizeof(UInt32) ); + + if (s->arr1 == NULL || s->arr2 == NULL || s->ftab == NULL) { + if (s->arr1 != NULL) BZFREE(s->arr1); + if (s->arr2 != NULL) BZFREE(s->arr2); + if (s->ftab != NULL) BZFREE(s->ftab); + if (s != NULL) BZFREE(s); + return BZ_MEM_ERROR; + } + + s->blockNo = 0; + s->state = BZ_S_INPUT; + s->mode = BZ_M_RUNNING; + s->combinedCRC = 0; + s->blockSize100k = blockSize100k; + s->nblockMAX = 100000 * blockSize100k - 19; + s->verbosity = verbosity; + s->workFactor = workFactor; + + s->block = (UChar*)s->arr2; + s->mtfv = (UInt16*)s->arr1; + s->zbits = NULL; + s->ptr = (UInt32*)s->arr1; + + strm->state = s; + strm->total_in_lo32 = 0; + strm->total_in_hi32 = 0; + strm->total_out_lo32 = 0; + strm->total_out_hi32 = 0; + init_RL ( s ); + prepare_new_block ( s ); + return BZ_OK; +} + + +/*---------------------------------------------------*/ +static +void add_pair_to_block ( EState* s ) +{ + Int32 i; + UChar ch = (UChar)(s->state_in_ch); + for (i = 0; i < s->state_in_len; i++) { + BZ_UPDATE_CRC( s->blockCRC, ch ); + } + s->inUse[s->state_in_ch] = True; + switch (s->state_in_len) { + case 1: + s->block[s->nblock] = (UChar)ch; s->nblock++; + break; + case 2: + s->block[s->nblock] = (UChar)ch; s->nblock++; + s->block[s->nblock] = (UChar)ch; s->nblock++; + break; + case 3: + s->block[s->nblock] = (UChar)ch; s->nblock++; + s->block[s->nblock] = (UChar)ch; s->nblock++; + s->block[s->nblock] = (UChar)ch; s->nblock++; + break; + default: + s->inUse[s->state_in_len-4] = True; + s->block[s->nblock] = (UChar)ch; s->nblock++; + s->block[s->nblock] = (UChar)ch; s->nblock++; + s->block[s->nblock] = (UChar)ch; s->nblock++; + s->block[s->nblock] = (UChar)ch; s->nblock++; + s->block[s->nblock] = ((UChar)(s->state_in_len-4)); + s->nblock++; + break; + } +} + + +/*---------------------------------------------------*/ +static +void flush_RL ( EState* s ) +{ + if (s->state_in_ch < 256) add_pair_to_block ( s ); + init_RL ( s ); +} + + +/*---------------------------------------------------*/ +#define ADD_CHAR_TO_BLOCK(zs,zchh0) \ +{ \ + UInt32 zchh = (UInt32)(zchh0); \ + /*-- fast track the common case --*/ \ + if (zchh != zs->state_in_ch && \ + zs->state_in_len == 1) { \ + UChar ch = (UChar)(zs->state_in_ch); \ + BZ_UPDATE_CRC( zs->blockCRC, ch ); \ + zs->inUse[zs->state_in_ch] = True; \ + zs->block[zs->nblock] = (UChar)ch; \ + zs->nblock++; \ + zs->state_in_ch = zchh; \ + } \ + else \ + /*-- general, uncommon cases --*/ \ + if (zchh != zs->state_in_ch || \ + zs->state_in_len == 255) { \ + if (zs->state_in_ch < 256) \ + add_pair_to_block ( zs ); \ + zs->state_in_ch = zchh; \ + zs->state_in_len = 1; \ + } else { \ + zs->state_in_len++; \ + } \ +} + + +/*---------------------------------------------------*/ +static +Bool copy_input_until_stop ( EState* s ) +{ + Bool progress_in = False; + + if (s->mode == BZ_M_RUNNING) { + + /*-- fast track the common case --*/ + while (True) { + /*-- block full? --*/ + if (s->nblock >= s->nblockMAX) break; + /*-- no input? --*/ + if (s->strm->avail_in == 0) break; + progress_in = True; + ADD_CHAR_TO_BLOCK ( s, (UInt32)(*((UChar*)(s->strm->next_in))) ); + s->strm->next_in++; + s->strm->avail_in--; + s->strm->total_in_lo32++; + if (s->strm->total_in_lo32 == 0) s->strm->total_in_hi32++; + } + + } else { + + /*-- general, uncommon case --*/ + while (True) { + /*-- block full? --*/ + if (s->nblock >= s->nblockMAX) break; + /*-- no input? --*/ + if (s->strm->avail_in == 0) break; + /*-- flush/finish end? --*/ + if (s->avail_in_expect == 0) break; + progress_in = True; + ADD_CHAR_TO_BLOCK ( s, (UInt32)(*((UChar*)(s->strm->next_in))) ); + s->strm->next_in++; + s->strm->avail_in--; + s->strm->total_in_lo32++; + if (s->strm->total_in_lo32 == 0) s->strm->total_in_hi32++; + s->avail_in_expect--; + } + } + return progress_in; +} + + +/*---------------------------------------------------*/ +static +Bool copy_output_until_stop ( EState* s ) +{ + Bool progress_out = False; + + while (True) { + + /*-- no output space? --*/ + if (s->strm->avail_out == 0) break; + + /*-- block done? --*/ + if (s->state_out_pos >= s->numZ) break; + + progress_out = True; + *(s->strm->next_out) = s->zbits[s->state_out_pos]; + s->state_out_pos++; + s->strm->avail_out--; + s->strm->next_out++; + s->strm->total_out_lo32++; + if (s->strm->total_out_lo32 == 0) s->strm->total_out_hi32++; + } + + return progress_out; +} + + +/*---------------------------------------------------*/ +static +Bool handle_compress ( bz_stream* strm ) +{ + Bool progress_in = False; + Bool progress_out = False; + EState* s = strm->state; + + while (True) { + + if (s->state == BZ_S_OUTPUT) { + progress_out |= copy_output_until_stop ( s ); + if (s->state_out_pos < s->numZ) break; + if (s->mode == BZ_M_FINISHING && + s->avail_in_expect == 0 && + isempty_RL(s)) break; + prepare_new_block ( s ); + s->state = BZ_S_INPUT; + if (s->mode == BZ_M_FLUSHING && + s->avail_in_expect == 0 && + isempty_RL(s)) break; + } + + if (s->state == BZ_S_INPUT) { + progress_in |= copy_input_until_stop ( s ); + if (s->mode != BZ_M_RUNNING && s->avail_in_expect == 0) { + flush_RL ( s ); + BZ2_compressBlock ( s, (Bool)(s->mode == BZ_M_FINISHING) ); + s->state = BZ_S_OUTPUT; + } + else + if (s->nblock >= s->nblockMAX) { + BZ2_compressBlock ( s, False ); + s->state = BZ_S_OUTPUT; + } + else + if (s->strm->avail_in == 0) { + break; + } + } + + } + + return progress_in || progress_out; +} + + +/*---------------------------------------------------*/ +int BZ_API(BZ2_bzCompress) ( bz_stream *strm, int action ) +{ + Bool progress; + EState* s; + if (strm == NULL) return BZ_PARAM_ERROR; + s = strm->state; + if (s == NULL) return BZ_PARAM_ERROR; + if (s->strm != strm) return BZ_PARAM_ERROR; + + preswitch: + switch (s->mode) { + + case BZ_M_IDLE: + return BZ_SEQUENCE_ERROR; + + case BZ_M_RUNNING: + if (action == BZ_RUN) { + progress = handle_compress ( strm ); + return progress ? BZ_RUN_OK : BZ_PARAM_ERROR; + } + else + if (action == BZ_FLUSH) { + s->avail_in_expect = strm->avail_in; + s->mode = BZ_M_FLUSHING; + goto preswitch; + } + else + if (action == BZ_FINISH) { + s->avail_in_expect = strm->avail_in; + s->mode = BZ_M_FINISHING; + goto preswitch; + } + else + return BZ_PARAM_ERROR; + + case BZ_M_FLUSHING: + if (action != BZ_FLUSH) return BZ_SEQUENCE_ERROR; + if (s->avail_in_expect != s->strm->avail_in) + return BZ_SEQUENCE_ERROR; + progress = handle_compress ( strm ); + if (s->avail_in_expect > 0 || !isempty_RL(s) || + s->state_out_pos < s->numZ) return BZ_FLUSH_OK; + s->mode = BZ_M_RUNNING; + return BZ_RUN_OK; + + case BZ_M_FINISHING: + if (action != BZ_FINISH) return BZ_SEQUENCE_ERROR; + if (s->avail_in_expect != s->strm->avail_in) + return BZ_SEQUENCE_ERROR; + progress = handle_compress ( strm ); + if (!progress) return BZ_SEQUENCE_ERROR; + if (s->avail_in_expect > 0 || !isempty_RL(s) || + s->state_out_pos < s->numZ) return BZ_FINISH_OK; + s->mode = BZ_M_IDLE; + return BZ_STREAM_END; + } + return BZ_OK; /*--not reached--*/ +} + + +/*---------------------------------------------------*/ +int BZ_API(BZ2_bzCompressEnd) ( bz_stream *strm ) +{ + EState* s; + if (strm == NULL) return BZ_PARAM_ERROR; + s = strm->state; + if (s == NULL) return BZ_PARAM_ERROR; + if (s->strm != strm) return BZ_PARAM_ERROR; + + if (s->arr1 != NULL) BZFREE(s->arr1); + if (s->arr2 != NULL) BZFREE(s->arr2); + if (s->ftab != NULL) BZFREE(s->ftab); + BZFREE(strm->state); + + strm->state = NULL; + + return BZ_OK; +} + + +/*---------------------------------------------------*/ +/*--- Decompression stuff ---*/ +/*---------------------------------------------------*/ + +/*---------------------------------------------------*/ +int BZ_API(BZ2_bzDecompressInit) + ( bz_stream* strm, + int verbosity, + int small ) +{ + DState* s; + + if (!bz_config_ok()) return BZ_CONFIG_ERROR; + + if (strm == NULL) return BZ_PARAM_ERROR; + if (small != 0 && small != 1) return BZ_PARAM_ERROR; + if (verbosity < 0 || verbosity > 4) return BZ_PARAM_ERROR; + + if (strm->bzalloc == NULL) strm->bzalloc = default_bzalloc; + if (strm->bzfree == NULL) strm->bzfree = default_bzfree; + + s = BZALLOC( sizeof(DState) ); + if (s == NULL) return BZ_MEM_ERROR; + s->strm = strm; + strm->state = s; + s->state = BZ_X_MAGIC_1; + s->bsLive = 0; + s->bsBuff = 0; + s->calculatedCombinedCRC = 0; + strm->total_in_lo32 = 0; + strm->total_in_hi32 = 0; + strm->total_out_lo32 = 0; + strm->total_out_hi32 = 0; + s->smallDecompress = (Bool)small; + s->ll4 = NULL; + s->ll16 = NULL; + s->tt = NULL; + s->currBlockNo = 0; + s->verbosity = verbosity; + + return BZ_OK; +} + + +/*---------------------------------------------------*/ +/* Return True iff data corruption is discovered. + Returns False if there is no problem. +*/ +static +Bool unRLE_obuf_to_output_FAST ( DState* s ) +{ + UChar k1; + + if (s->blockRandomised) { + + while (True) { + /* try to finish existing run */ + while (True) { + if (s->strm->avail_out == 0) return False; + if (s->state_out_len == 0) break; + *( (UChar*)(s->strm->next_out) ) = s->state_out_ch; + BZ_UPDATE_CRC ( s->calculatedBlockCRC, s->state_out_ch ); + s->state_out_len--; + s->strm->next_out++; + s->strm->avail_out--; + s->strm->total_out_lo32++; + if (s->strm->total_out_lo32 == 0) s->strm->total_out_hi32++; + } + + /* can a new run be started? */ + if (s->nblock_used == s->save_nblock+1) return False; + + /* Only caused by corrupt data stream? */ + if (s->nblock_used > s->save_nblock+1) + return True; + + s->state_out_len = 1; + s->state_out_ch = s->k0; + BZ_GET_FAST(k1); BZ_RAND_UPD_MASK; + k1 ^= BZ_RAND_MASK; s->nblock_used++; + if (s->nblock_used == s->save_nblock+1) continue; + if (k1 != s->k0) { s->k0 = k1; continue; }; + + s->state_out_len = 2; + BZ_GET_FAST(k1); BZ_RAND_UPD_MASK; + k1 ^= BZ_RAND_MASK; s->nblock_used++; + if (s->nblock_used == s->save_nblock+1) continue; + if (k1 != s->k0) { s->k0 = k1; continue; }; + + s->state_out_len = 3; + BZ_GET_FAST(k1); BZ_RAND_UPD_MASK; + k1 ^= BZ_RAND_MASK; s->nblock_used++; + if (s->nblock_used == s->save_nblock+1) continue; + if (k1 != s->k0) { s->k0 = k1; continue; }; + + BZ_GET_FAST(k1); BZ_RAND_UPD_MASK; + k1 ^= BZ_RAND_MASK; s->nblock_used++; + s->state_out_len = ((Int32)k1) + 4; + BZ_GET_FAST(s->k0); BZ_RAND_UPD_MASK; + s->k0 ^= BZ_RAND_MASK; s->nblock_used++; + } + + } else { + + /* restore */ + UInt32 c_calculatedBlockCRC = s->calculatedBlockCRC; + UChar c_state_out_ch = s->state_out_ch; + Int32 c_state_out_len = s->state_out_len; + Int32 c_nblock_used = s->nblock_used; + Int32 c_k0 = s->k0; + UInt32* c_tt = s->tt; + UInt32 c_tPos = s->tPos; + char* cs_next_out = s->strm->next_out; + unsigned int cs_avail_out = s->strm->avail_out; + Int32 ro_blockSize100k = s->blockSize100k; + /* end restore */ + + UInt32 avail_out_INIT = cs_avail_out; + Int32 s_save_nblockPP = s->save_nblock+1; + unsigned int total_out_lo32_old; + + while (True) { + + /* try to finish existing run */ + if (c_state_out_len > 0) { + while (True) { + if (cs_avail_out == 0) goto return_notr; + if (c_state_out_len == 1) break; + *( (UChar*)(cs_next_out) ) = c_state_out_ch; + BZ_UPDATE_CRC ( c_calculatedBlockCRC, c_state_out_ch ); + c_state_out_len--; + cs_next_out++; + cs_avail_out--; + } + s_state_out_len_eq_one: + { + if (cs_avail_out == 0) { + c_state_out_len = 1; goto return_notr; + }; + *( (UChar*)(cs_next_out) ) = c_state_out_ch; + BZ_UPDATE_CRC ( c_calculatedBlockCRC, c_state_out_ch ); + cs_next_out++; + cs_avail_out--; + } + } + /* Only caused by corrupt data stream? */ + if (c_nblock_used > s_save_nblockPP) + return True; + + /* can a new run be started? */ + if (c_nblock_used == s_save_nblockPP) { + c_state_out_len = 0; goto return_notr; + }; + c_state_out_ch = c_k0; + BZ_GET_FAST_C(k1); c_nblock_used++; + if (k1 != c_k0) { + c_k0 = k1; goto s_state_out_len_eq_one; + }; + if (c_nblock_used == s_save_nblockPP) + goto s_state_out_len_eq_one; + + c_state_out_len = 2; + BZ_GET_FAST_C(k1); c_nblock_used++; + if (c_nblock_used == s_save_nblockPP) continue; + if (k1 != c_k0) { c_k0 = k1; continue; }; + + c_state_out_len = 3; + BZ_GET_FAST_C(k1); c_nblock_used++; + if (c_nblock_used == s_save_nblockPP) continue; + if (k1 != c_k0) { c_k0 = k1; continue; }; + + BZ_GET_FAST_C(k1); c_nblock_used++; + c_state_out_len = ((Int32)k1) + 4; + BZ_GET_FAST_C(c_k0); c_nblock_used++; + } + + return_notr: + total_out_lo32_old = s->strm->total_out_lo32; + s->strm->total_out_lo32 += (avail_out_INIT - cs_avail_out); + if (s->strm->total_out_lo32 < total_out_lo32_old) + s->strm->total_out_hi32++; + + /* save */ + s->calculatedBlockCRC = c_calculatedBlockCRC; + s->state_out_ch = c_state_out_ch; + s->state_out_len = c_state_out_len; + s->nblock_used = c_nblock_used; + s->k0 = c_k0; + s->tt = c_tt; + s->tPos = c_tPos; + s->strm->next_out = cs_next_out; + s->strm->avail_out = cs_avail_out; + /* end save */ + } + return False; +} + + + +/*---------------------------------------------------*/ +__inline__ Int32 BZ2_indexIntoF ( Int32 indx, Int32 *cftab ) +{ + Int32 nb, na, mid; + nb = 0; + na = 256; + do { + mid = (nb + na) >> 1; + if (indx >= cftab[mid]) nb = mid; else na = mid; + } + while (na - nb != 1); + return nb; +} + + +/*---------------------------------------------------*/ +/* Return True iff data corruption is discovered. + Returns False if there is no problem. +*/ +static +Bool unRLE_obuf_to_output_SMALL ( DState* s ) +{ + UChar k1; + + if (s->blockRandomised) { + + while (True) { + /* try to finish existing run */ + while (True) { + if (s->strm->avail_out == 0) return False; + if (s->state_out_len == 0) break; + *( (UChar*)(s->strm->next_out) ) = s->state_out_ch; + BZ_UPDATE_CRC ( s->calculatedBlockCRC, s->state_out_ch ); + s->state_out_len--; + s->strm->next_out++; + s->strm->avail_out--; + s->strm->total_out_lo32++; + if (s->strm->total_out_lo32 == 0) s->strm->total_out_hi32++; + } + + /* can a new run be started? */ + if (s->nblock_used == s->save_nblock+1) return False; + + /* Only caused by corrupt data stream? */ + if (s->nblock_used > s->save_nblock+1) + return True; + + s->state_out_len = 1; + s->state_out_ch = s->k0; + BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK; + k1 ^= BZ_RAND_MASK; s->nblock_used++; + if (s->nblock_used == s->save_nblock+1) continue; + if (k1 != s->k0) { s->k0 = k1; continue; }; + + s->state_out_len = 2; + BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK; + k1 ^= BZ_RAND_MASK; s->nblock_used++; + if (s->nblock_used == s->save_nblock+1) continue; + if (k1 != s->k0) { s->k0 = k1; continue; }; + + s->state_out_len = 3; + BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK; + k1 ^= BZ_RAND_MASK; s->nblock_used++; + if (s->nblock_used == s->save_nblock+1) continue; + if (k1 != s->k0) { s->k0 = k1; continue; }; + + BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK; + k1 ^= BZ_RAND_MASK; s->nblock_used++; + s->state_out_len = ((Int32)k1) + 4; + BZ_GET_SMALL(s->k0); BZ_RAND_UPD_MASK; + s->k0 ^= BZ_RAND_MASK; s->nblock_used++; + } + + } else { + + while (True) { + /* try to finish existing run */ + while (True) { + if (s->strm->avail_out == 0) return False; + if (s->state_out_len == 0) break; + *( (UChar*)(s->strm->next_out) ) = s->state_out_ch; + BZ_UPDATE_CRC ( s->calculatedBlockCRC, s->state_out_ch ); + s->state_out_len--; + s->strm->next_out++; + s->strm->avail_out--; + s->strm->total_out_lo32++; + if (s->strm->total_out_lo32 == 0) s->strm->total_out_hi32++; + } + + /* can a new run be started? */ + if (s->nblock_used == s->save_nblock+1) return False; + + /* Only caused by corrupt data stream? */ + if (s->nblock_used > s->save_nblock+1) + return True; + + s->state_out_len = 1; + s->state_out_ch = s->k0; + BZ_GET_SMALL(k1); s->nblock_used++; + if (s->nblock_used == s->save_nblock+1) continue; + if (k1 != s->k0) { s->k0 = k1; continue; }; + + s->state_out_len = 2; + BZ_GET_SMALL(k1); s->nblock_used++; + if (s->nblock_used == s->save_nblock+1) continue; + if (k1 != s->k0) { s->k0 = k1; continue; }; + + s->state_out_len = 3; + BZ_GET_SMALL(k1); s->nblock_used++; + if (s->nblock_used == s->save_nblock+1) continue; + if (k1 != s->k0) { s->k0 = k1; continue; }; + + BZ_GET_SMALL(k1); s->nblock_used++; + s->state_out_len = ((Int32)k1) + 4; + BZ_GET_SMALL(s->k0); s->nblock_used++; + } + + } +} + + +/*---------------------------------------------------*/ +int BZ_API(BZ2_bzDecompress) ( bz_stream *strm ) +{ + Bool corrupt; + DState* s; + if (strm == NULL) return BZ_PARAM_ERROR; + s = strm->state; + if (s == NULL) return BZ_PARAM_ERROR; + if (s->strm != strm) return BZ_PARAM_ERROR; + + while (True) { + if (s->state == BZ_X_IDLE) return BZ_SEQUENCE_ERROR; + if (s->state == BZ_X_OUTPUT) { + if (s->smallDecompress) + corrupt = unRLE_obuf_to_output_SMALL ( s ); else + corrupt = unRLE_obuf_to_output_FAST ( s ); + if (corrupt) return BZ_DATA_ERROR; + if (s->nblock_used == s->save_nblock+1 && s->state_out_len == 0) { + BZ_FINALISE_CRC ( s->calculatedBlockCRC ); + if (s->verbosity >= 3) + VPrintf2 ( " {0x%08x, 0x%08x}", s->storedBlockCRC, + s->calculatedBlockCRC ); + if (s->verbosity >= 2) VPrintf0 ( "]" ); + if (s->calculatedBlockCRC != s->storedBlockCRC) + return BZ_DATA_ERROR; + s->calculatedCombinedCRC + = (s->calculatedCombinedCRC << 1) | + (s->calculatedCombinedCRC >> 31); + s->calculatedCombinedCRC ^= s->calculatedBlockCRC; + s->state = BZ_X_BLKHDR_1; + } else { + return BZ_OK; + } + } + if (s->state >= BZ_X_MAGIC_1) { + Int32 r = BZ2_decompress ( s ); + if (r == BZ_STREAM_END) { + if (s->verbosity >= 3) + VPrintf2 ( "\n combined CRCs: stored = 0x%08x, computed = 0x%08x", + s->storedCombinedCRC, s->calculatedCombinedCRC ); + if (s->calculatedCombinedCRC != s->storedCombinedCRC) + return BZ_DATA_ERROR; + return r; + } + if (s->state != BZ_X_OUTPUT) return r; + } + } + + AssertH ( 0, 6001 ); + + return 0; /*NOTREACHED*/ +} + + +/*---------------------------------------------------*/ +int BZ_API(BZ2_bzDecompressEnd) ( bz_stream *strm ) +{ + DState* s; + if (strm == NULL) return BZ_PARAM_ERROR; + s = strm->state; + if (s == NULL) return BZ_PARAM_ERROR; + if (s->strm != strm) return BZ_PARAM_ERROR; + + if (s->tt != NULL) BZFREE(s->tt); + if (s->ll16 != NULL) BZFREE(s->ll16); + if (s->ll4 != NULL) BZFREE(s->ll4); + + BZFREE(strm->state); + strm->state = NULL; + + return BZ_OK; +} + + +#ifndef BZ_NO_STDIO +/*---------------------------------------------------*/ +/*--- File I/O stuff ---*/ +/*---------------------------------------------------*/ + +#define BZ_SETERR(eee) \ +{ \ + if (bzerror != NULL) *bzerror = eee; \ + if (bzf != NULL) bzf->lastErr = eee; \ +} + +typedef + struct { + FILE* handle; + Char buf[BZ_MAX_UNUSED]; + Int32 bufN; + Bool writing; + bz_stream strm; + Int32 lastErr; + Bool initialisedOk; + } + bzFile; + + +/*---------------------------------------------*/ +static Bool myfeof ( FILE* f ) +{ + Int32 c = fgetc ( f ); + if (c == EOF) return True; + ungetc ( c, f ); + return False; +} + + +/*---------------------------------------------------*/ +BZFILE* BZ_API(BZ2_bzWriteOpen) + ( int* bzerror, + FILE* f, + int blockSize100k, + int verbosity, + int workFactor ) +{ + Int32 ret; + bzFile* bzf = NULL; + + BZ_SETERR(BZ_OK); + + if (f == NULL || + (blockSize100k < 1 || blockSize100k > 9) || + (workFactor < 0 || workFactor > 250) || + (verbosity < 0 || verbosity > 4)) + { BZ_SETERR(BZ_PARAM_ERROR); return NULL; }; + + if (ferror(f)) + { BZ_SETERR(BZ_IO_ERROR); return NULL; }; + + bzf = malloc ( sizeof(bzFile) ); + if (bzf == NULL) + { BZ_SETERR(BZ_MEM_ERROR); return NULL; }; + + BZ_SETERR(BZ_OK); + bzf->initialisedOk = False; + bzf->bufN = 0; + bzf->handle = f; + bzf->writing = True; + bzf->strm.bzalloc = NULL; + bzf->strm.bzfree = NULL; + bzf->strm.opaque = NULL; + + if (workFactor == 0) workFactor = 30; + ret = BZ2_bzCompressInit ( &(bzf->strm), blockSize100k, + verbosity, workFactor ); + if (ret != BZ_OK) + { BZ_SETERR(ret); free(bzf); return NULL; }; + + bzf->strm.avail_in = 0; + bzf->initialisedOk = True; + return bzf; +} + + + +/*---------------------------------------------------*/ +void BZ_API(BZ2_bzWrite) + ( int* bzerror, + BZFILE* b, + void* buf, + int len ) +{ + Int32 n, n2, ret; + bzFile* bzf = (bzFile*)b; + + BZ_SETERR(BZ_OK); + if (bzf == NULL || buf == NULL || len < 0) + { BZ_SETERR(BZ_PARAM_ERROR); return; }; + if (!(bzf->writing)) + { BZ_SETERR(BZ_SEQUENCE_ERROR); return; }; + if (ferror(bzf->handle)) + { BZ_SETERR(BZ_IO_ERROR); return; }; + + if (len == 0) + { BZ_SETERR(BZ_OK); return; }; + + bzf->strm.avail_in = len; + bzf->strm.next_in = buf; + + while (True) { + bzf->strm.avail_out = BZ_MAX_UNUSED; + bzf->strm.next_out = bzf->buf; + ret = BZ2_bzCompress ( &(bzf->strm), BZ_RUN ); + if (ret != BZ_RUN_OK) + { BZ_SETERR(ret); return; }; + + if (bzf->strm.avail_out < BZ_MAX_UNUSED) { + n = BZ_MAX_UNUSED - bzf->strm.avail_out; + n2 = fwrite ( (void*)(bzf->buf), sizeof(UChar), + n, bzf->handle ); + if (n != n2 || ferror(bzf->handle)) + { BZ_SETERR(BZ_IO_ERROR); return; }; + } + + if (bzf->strm.avail_in == 0) + { BZ_SETERR(BZ_OK); return; }; + } +} + + +/*---------------------------------------------------*/ +void BZ_API(BZ2_bzWriteClose) + ( int* bzerror, + BZFILE* b, + int abandon, + unsigned int* nbytes_in, + unsigned int* nbytes_out ) +{ + BZ2_bzWriteClose64 ( bzerror, b, abandon, + nbytes_in, NULL, nbytes_out, NULL ); +} + + +void BZ_API(BZ2_bzWriteClose64) + ( int* bzerror, + BZFILE* b, + int abandon, + unsigned int* nbytes_in_lo32, + unsigned int* nbytes_in_hi32, + unsigned int* nbytes_out_lo32, + unsigned int* nbytes_out_hi32 ) +{ + Int32 n, n2, ret; + bzFile* bzf = (bzFile*)b; + + if (bzf == NULL) + { BZ_SETERR(BZ_OK); return; }; + if (!(bzf->writing)) + { BZ_SETERR(BZ_SEQUENCE_ERROR); return; }; + if (ferror(bzf->handle)) + { BZ_SETERR(BZ_IO_ERROR); return; }; + + if (nbytes_in_lo32 != NULL) *nbytes_in_lo32 = 0; + if (nbytes_in_hi32 != NULL) *nbytes_in_hi32 = 0; + if (nbytes_out_lo32 != NULL) *nbytes_out_lo32 = 0; + if (nbytes_out_hi32 != NULL) *nbytes_out_hi32 = 0; + + if ((!abandon) && bzf->lastErr == BZ_OK) { + while (True) { + bzf->strm.avail_out = BZ_MAX_UNUSED; + bzf->strm.next_out = bzf->buf; + ret = BZ2_bzCompress ( &(bzf->strm), BZ_FINISH ); + if (ret != BZ_FINISH_OK && ret != BZ_STREAM_END) + { BZ_SETERR(ret); return; }; + + if (bzf->strm.avail_out < BZ_MAX_UNUSED) { + n = BZ_MAX_UNUSED - bzf->strm.avail_out; + n2 = fwrite ( (void*)(bzf->buf), sizeof(UChar), + n, bzf->handle ); + if (n != n2 || ferror(bzf->handle)) + { BZ_SETERR(BZ_IO_ERROR); return; }; + } + + if (ret == BZ_STREAM_END) break; + } + } + + if ( !abandon && !ferror ( bzf->handle ) ) { + fflush ( bzf->handle ); + if (ferror(bzf->handle)) + { BZ_SETERR(BZ_IO_ERROR); return; }; + } + + if (nbytes_in_lo32 != NULL) + *nbytes_in_lo32 = bzf->strm.total_in_lo32; + if (nbytes_in_hi32 != NULL) + *nbytes_in_hi32 = bzf->strm.total_in_hi32; + if (nbytes_out_lo32 != NULL) + *nbytes_out_lo32 = bzf->strm.total_out_lo32; + if (nbytes_out_hi32 != NULL) + *nbytes_out_hi32 = bzf->strm.total_out_hi32; + + BZ_SETERR(BZ_OK); + BZ2_bzCompressEnd ( &(bzf->strm) ); + free ( bzf ); +} + + +/*---------------------------------------------------*/ +BZFILE* BZ_API(BZ2_bzReadOpen) + ( int* bzerror, + FILE* f, + int verbosity, + int small, + void* unused, + int nUnused ) +{ + bzFile* bzf = NULL; + int ret; + + BZ_SETERR(BZ_OK); + + if (f == NULL || + (small != 0 && small != 1) || + (verbosity < 0 || verbosity > 4) || + (unused == NULL && nUnused != 0) || + (unused != NULL && (nUnused < 0 || nUnused > BZ_MAX_UNUSED))) + { BZ_SETERR(BZ_PARAM_ERROR); return NULL; }; + + if (ferror(f)) + { BZ_SETERR(BZ_IO_ERROR); return NULL; }; + + bzf = malloc ( sizeof(bzFile) ); + if (bzf == NULL) + { BZ_SETERR(BZ_MEM_ERROR); return NULL; }; + + BZ_SETERR(BZ_OK); + + bzf->initialisedOk = False; + bzf->handle = f; + bzf->bufN = 0; + bzf->writing = False; + bzf->strm.bzalloc = NULL; + bzf->strm.bzfree = NULL; + bzf->strm.opaque = NULL; + + while (nUnused > 0) { + bzf->buf[bzf->bufN] = *((UChar*)(unused)); bzf->bufN++; + unused = ((void*)( 1 + ((UChar*)(unused)) )); + nUnused--; + } + + ret = BZ2_bzDecompressInit ( &(bzf->strm), verbosity, small ); + if (ret != BZ_OK) + { BZ_SETERR(ret); free(bzf); return NULL; }; + + bzf->strm.avail_in = bzf->bufN; + bzf->strm.next_in = bzf->buf; + + bzf->initialisedOk = True; + return bzf; +} + + +/*---------------------------------------------------*/ +void BZ_API(BZ2_bzReadClose) ( int *bzerror, BZFILE *b ) +{ + bzFile* bzf = (bzFile*)b; + + BZ_SETERR(BZ_OK); + if (bzf == NULL) + { BZ_SETERR(BZ_OK); return; }; + + if (bzf->writing) + { BZ_SETERR(BZ_SEQUENCE_ERROR); return; }; + + if (bzf->initialisedOk) + (void)BZ2_bzDecompressEnd ( &(bzf->strm) ); + free ( bzf ); +} + + +/*---------------------------------------------------*/ +int BZ_API(BZ2_bzRead) + ( int* bzerror, + BZFILE* b, + void* buf, + int len ) +{ + Int32 n, ret; + bzFile* bzf = (bzFile*)b; + + BZ_SETERR(BZ_OK); + + if (bzf == NULL || buf == NULL || len < 0) + { BZ_SETERR(BZ_PARAM_ERROR); return 0; }; + + if (bzf->writing) + { BZ_SETERR(BZ_SEQUENCE_ERROR); return 0; }; + + if (len == 0) + { BZ_SETERR(BZ_OK); return 0; }; + + bzf->strm.avail_out = len; + bzf->strm.next_out = buf; + + while (True) { + + if (ferror(bzf->handle)) + { BZ_SETERR(BZ_IO_ERROR); return 0; }; + + if (bzf->strm.avail_in == 0 && !myfeof(bzf->handle)) { + n = fread ( bzf->buf, sizeof(UChar), + BZ_MAX_UNUSED, bzf->handle ); + if (ferror(bzf->handle)) + { BZ_SETERR(BZ_IO_ERROR); return 0; }; + bzf->bufN = n; + bzf->strm.avail_in = bzf->bufN; + bzf->strm.next_in = bzf->buf; + } + + ret = BZ2_bzDecompress ( &(bzf->strm) ); + + if (ret != BZ_OK && ret != BZ_STREAM_END) + { BZ_SETERR(ret); return 0; }; + + if (ret == BZ_OK && myfeof(bzf->handle) && + bzf->strm.avail_in == 0 && bzf->strm.avail_out > 0) + { BZ_SETERR(BZ_UNEXPECTED_EOF); return 0; }; + + if (ret == BZ_STREAM_END) + { BZ_SETERR(BZ_STREAM_END); + return len - bzf->strm.avail_out; }; + if (bzf->strm.avail_out == 0) + { BZ_SETERR(BZ_OK); return len; }; + + } + + return 0; /*not reached*/ +} + + +/*---------------------------------------------------*/ +void BZ_API(BZ2_bzReadGetUnused) + ( int* bzerror, + BZFILE* b, + void** unused, + int* nUnused ) +{ + bzFile* bzf = (bzFile*)b; + if (bzf == NULL) + { BZ_SETERR(BZ_PARAM_ERROR); return; }; + if (bzf->lastErr != BZ_STREAM_END) + { BZ_SETERR(BZ_SEQUENCE_ERROR); return; }; + if (unused == NULL || nUnused == NULL) + { BZ_SETERR(BZ_PARAM_ERROR); return; }; + + BZ_SETERR(BZ_OK); + *nUnused = bzf->strm.avail_in; + *unused = bzf->strm.next_in; +} +#endif + + +/*---------------------------------------------------*/ +/*--- Misc convenience stuff ---*/ +/*---------------------------------------------------*/ + +/*---------------------------------------------------*/ +int BZ_API(BZ2_bzBuffToBuffCompress) + ( char* dest, + unsigned int* destLen, + char* source, + unsigned int sourceLen, + int blockSize100k, + int verbosity, + int workFactor ) +{ + bz_stream strm; + int ret; + + if (dest == NULL || destLen == NULL || + source == NULL || + blockSize100k < 1 || blockSize100k > 9 || + verbosity < 0 || verbosity > 4 || + workFactor < 0 || workFactor > 250) + return BZ_PARAM_ERROR; + + if (workFactor == 0) workFactor = 30; + strm.bzalloc = NULL; + strm.bzfree = NULL; + strm.opaque = NULL; + ret = BZ2_bzCompressInit ( &strm, blockSize100k, + verbosity, workFactor ); + if (ret != BZ_OK) return ret; + + strm.next_in = source; + strm.next_out = dest; + strm.avail_in = sourceLen; + strm.avail_out = *destLen; + + ret = BZ2_bzCompress ( &strm, BZ_FINISH ); + if (ret == BZ_FINISH_OK) goto output_overflow; + if (ret != BZ_STREAM_END) goto errhandler; + + /* normal termination */ + *destLen -= strm.avail_out; + BZ2_bzCompressEnd ( &strm ); + return BZ_OK; + + output_overflow: + BZ2_bzCompressEnd ( &strm ); + return BZ_OUTBUFF_FULL; + + errhandler: + BZ2_bzCompressEnd ( &strm ); + return ret; +} + + +/*---------------------------------------------------*/ +int BZ_API(BZ2_bzBuffToBuffDecompress) + ( char* dest, + unsigned int* destLen, + char* source, + unsigned int sourceLen, + int small, + int verbosity ) +{ + bz_stream strm; + int ret; + + if (dest == NULL || destLen == NULL || + source == NULL || + (small != 0 && small != 1) || + verbosity < 0 || verbosity > 4) + return BZ_PARAM_ERROR; + + strm.bzalloc = NULL; + strm.bzfree = NULL; + strm.opaque = NULL; + ret = BZ2_bzDecompressInit ( &strm, verbosity, small ); + if (ret != BZ_OK) return ret; + + strm.next_in = source; + strm.next_out = dest; + strm.avail_in = sourceLen; + strm.avail_out = *destLen; + + ret = BZ2_bzDecompress ( &strm ); + if (ret == BZ_OK) goto output_overflow_or_eof; + if (ret != BZ_STREAM_END) goto errhandler; + + /* normal termination */ + *destLen -= strm.avail_out; + BZ2_bzDecompressEnd ( &strm ); + return BZ_OK; + + output_overflow_or_eof: + if (strm.avail_out > 0) { + BZ2_bzDecompressEnd ( &strm ); + return BZ_UNEXPECTED_EOF; + } else { + BZ2_bzDecompressEnd ( &strm ); + return BZ_OUTBUFF_FULL; + }; + + errhandler: + BZ2_bzDecompressEnd ( &strm ); + return ret; +} + + +/*---------------------------------------------------*/ +/*-- + Code contributed by Yoshioka Tsuneo (tsuneo@rr.iij4u.or.jp) + to support better zlib compatibility. + This code is not _officially_ part of libbzip2 (yet); + I haven't tested it, documented it, or considered the + threading-safeness of it. + If this code breaks, please contact both Yoshioka and me. +--*/ +/*---------------------------------------------------*/ + +/*---------------------------------------------------*/ +/*-- + return version like "0.9.5d, 4-Sept-1999". +--*/ +const char * BZ_API(BZ2_bzlibVersion)(void) +{ + return BZ_VERSION; +} + + +#ifndef BZ_NO_STDIO +/*---------------------------------------------------*/ + +#if defined(_WIN32) || defined(OS2) || defined(MSDOS) +# include <fcntl.h> +# include <io.h> +# define SET_BINARY_MODE(file) setmode(fileno(file),O_BINARY) +#else +# define SET_BINARY_MODE(file) +#endif +static +BZFILE * bzopen_or_bzdopen + ( const char *path, /* no use when bzdopen */ + int fd, /* no use when bzdopen */ + const char *mode, + int open_mode) /* bzopen: 0, bzdopen:1 */ +{ + int bzerr; + char unused[BZ_MAX_UNUSED]; + int blockSize100k = 9; + int writing = 0; + char mode2[10] = ""; + FILE *fp = NULL; + BZFILE *bzfp = NULL; + int verbosity = 0; + int workFactor = 30; + int smallMode = 0; + int nUnused = 0; + + if (mode == NULL) return NULL; + while (*mode) { + switch (*mode) { + case 'r': + writing = 0; break; + case 'w': + writing = 1; break; + case 's': + smallMode = 1; break; + default: + if (isdigit((int)(*mode))) { + blockSize100k = *mode-BZ_HDR_0; + } + } + mode++; + } + strcat(mode2, writing ? "w" : "r" ); + strcat(mode2,"b"); /* binary mode */ + + if (open_mode==0) { + if (path==NULL || strcmp(path,"")==0) { + fp = (writing ? stdout : stdin); + SET_BINARY_MODE(fp); + } else { + fp = fopen(path,mode2); + } + } else { +#ifdef BZ_STRICT_ANSI + fp = NULL; +#else + fp = fdopen(fd,mode2); +#endif + } + if (fp == NULL) return NULL; + + if (writing) { + /* Guard against total chaos and anarchy -- JRS */ + if (blockSize100k < 1) blockSize100k = 1; + if (blockSize100k > 9) blockSize100k = 9; + bzfp = BZ2_bzWriteOpen(&bzerr,fp,blockSize100k, + verbosity,workFactor); + } else { + bzfp = BZ2_bzReadOpen(&bzerr,fp,verbosity,smallMode, + unused,nUnused); + } + if (bzfp == NULL) { + if (fp != stdin && fp != stdout) fclose(fp); + return NULL; + } + return bzfp; +} + + +/*---------------------------------------------------*/ +/*-- + open file for read or write. + ex) bzopen("file","w9") + case path="" or NULL => use stdin or stdout. +--*/ +BZFILE * BZ_API(BZ2_bzopen) + ( const char *path, + const char *mode ) +{ + return bzopen_or_bzdopen(path,-1,mode,/*bzopen*/0); +} + + +/*---------------------------------------------------*/ +BZFILE * BZ_API(BZ2_bzdopen) + ( int fd, + const char *mode ) +{ + return bzopen_or_bzdopen(NULL,fd,mode,/*bzdopen*/1); +} + + +/*---------------------------------------------------*/ +int BZ_API(BZ2_bzread) (BZFILE* b, void* buf, int len ) +{ + int bzerr, nread; + if (((bzFile*)b)->lastErr == BZ_STREAM_END) return 0; + nread = BZ2_bzRead(&bzerr,b,buf,len); + if (bzerr == BZ_OK || bzerr == BZ_STREAM_END) { + return nread; + } else { + return -1; + } +} + + +/*---------------------------------------------------*/ +int BZ_API(BZ2_bzwrite) (BZFILE* b, void* buf, int len ) +{ + int bzerr; + + BZ2_bzWrite(&bzerr,b,buf,len); + if(bzerr == BZ_OK){ + return len; + }else{ + return -1; + } +} + + +/*---------------------------------------------------*/ +int BZ_API(BZ2_bzflush) (BZFILE *b) +{ + /* do nothing now... */ + return 0; +} + + +/*---------------------------------------------------*/ +void BZ_API(BZ2_bzclose) (BZFILE* b) +{ + int bzerr; + FILE *fp; + + if (b==NULL) {return;} + fp = ((bzFile *)b)->handle; + if(((bzFile*)b)->writing){ + BZ2_bzWriteClose(&bzerr,b,0,NULL,NULL); + if(bzerr != BZ_OK){ + BZ2_bzWriteClose(NULL,b,1,NULL,NULL); + } + }else{ + BZ2_bzReadClose(&bzerr,b); + } + if(fp!=stdin && fp!=stdout){ + fclose(fp); + } +} + + +/*---------------------------------------------------*/ +/*-- + return last error code +--*/ +static const char *bzerrorstrings[] = { + "OK" + ,"SEQUENCE_ERROR" + ,"PARAM_ERROR" + ,"MEM_ERROR" + ,"DATA_ERROR" + ,"DATA_ERROR_MAGIC" + ,"IO_ERROR" + ,"UNEXPECTED_EOF" + ,"OUTBUFF_FULL" + ,"CONFIG_ERROR" + ,"???" /* for future */ + ,"???" /* for future */ + ,"???" /* for future */ + ,"???" /* for future */ + ,"???" /* for future */ + ,"???" /* for future */ +}; + + +const char * BZ_API(BZ2_bzerror) (BZFILE *b, int *errnum) +{ + int err = ((bzFile *)b)->lastErr; + + if(err>0) err = 0; + *errnum = err; + return bzerrorstrings[err*-1]; +} +#endif + + +/*-------------------------------------------------------------*/ +/*--- end bzlib.c ---*/ +/*-------------------------------------------------------------*/ diff --git a/src/misc/bzlib/bzlib.h b/src/misc/bzlib/bzlib.h new file mode 100644 index 00000000..798f248c --- /dev/null +++ b/src/misc/bzlib/bzlib.h @@ -0,0 +1,286 @@ + +/*-------------------------------------------------------------*/ +/*--- Public header file for the library. ---*/ +/*--- bzlib.h ---*/ +/*-------------------------------------------------------------*/ + +/* ------------------------------------------------------------------ + This file is part of bzip2/libbzip2, a program and library for + lossless, block-sorting data compression. + + bzip2/libbzip2 version 1.0.5 of 10 December 2007 + Copyright (C) 1996-2007 Julian Seward <jseward@bzip.org> + + Please read the WARNING, DISCLAIMER and PATENTS sections in the + README file. + + This program is released under the terms of the license contained + in the file LICENSE. + ------------------------------------------------------------------ */ + +//#define O_BINARY 0 +#ifdef __STDC__ +#undef __STDC__ +#endif + +#ifndef _BZLIB_H +#define _BZLIB_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define BZ_RUN 0 +#define BZ_FLUSH 1 +#define BZ_FINISH 2 + +#define BZ_OK 0 +#define BZ_RUN_OK 1 +#define BZ_FLUSH_OK 2 +#define BZ_FINISH_OK 3 +#define BZ_STREAM_END 4 +#define BZ_SEQUENCE_ERROR (-1) +#define BZ_PARAM_ERROR (-2) +#define BZ_MEM_ERROR (-3) +#define BZ_DATA_ERROR (-4) +#define BZ_DATA_ERROR_MAGIC (-5) +#define BZ_IO_ERROR (-6) +#define BZ_UNEXPECTED_EOF (-7) +#define BZ_OUTBUFF_FULL (-8) +#define BZ_CONFIG_ERROR (-9) + +typedef + struct { + char *next_in; + unsigned int avail_in; + unsigned int total_in_lo32; + unsigned int total_in_hi32; + + char *next_out; + unsigned int avail_out; + unsigned int total_out_lo32; + unsigned int total_out_hi32; + + void *state; + + void *(*bzalloc)(void *,int,int); + void (*bzfree)(void *,void *); + void *opaque; + } + bz_stream; + + +#ifndef BZ_IMPORT +#define BZ_EXPORT +#endif + +#ifndef BZ_NO_STDIO +/* Need a definitition for FILE */ +#include <stdio.h> +#endif + +#ifdef _WIN32 +# include <windows.h> +# ifdef small + /* windows.h define small to char */ +# undef small +# endif +# ifdef BZ_EXPORT +# define BZ_API(func) WINAPI func +# define BZ_EXTERN extern +# else + /* import windows dll dynamically */ +# define BZ_API(func) (WINAPI * func) +# define BZ_EXTERN +# endif +#else +# define BZ_API(func) func +# define BZ_EXTERN extern +#endif + + +/*-- Core (low-level) library functions --*/ + +BZ_EXTERN int BZ_API(BZ2_bzCompressInit) ( + bz_stream* strm, + int blockSize100k, + int verbosity, + int workFactor + ); + +BZ_EXTERN int BZ_API(BZ2_bzCompress) ( + bz_stream* strm, + int action + ); + +BZ_EXTERN int BZ_API(BZ2_bzCompressEnd) ( + bz_stream* strm + ); + +BZ_EXTERN int BZ_API(BZ2_bzDecompressInit) ( + bz_stream *strm, + int verbosity, + int small + ); + +BZ_EXTERN int BZ_API(BZ2_bzDecompress) ( + bz_stream* strm + ); + +BZ_EXTERN int BZ_API(BZ2_bzDecompressEnd) ( + bz_stream *strm + ); + + + +/*-- High(er) level library functions --*/ + +#ifndef BZ_NO_STDIO +#define BZ_MAX_UNUSED 5000 + +typedef void BZFILE; + +BZ_EXTERN BZFILE* BZ_API(BZ2_bzReadOpen) ( + int* bzerror, + FILE* f, + int verbosity, + int small, + void* unused, + int nUnused + ); + +BZ_EXTERN void BZ_API(BZ2_bzReadClose) ( + int* bzerror, + BZFILE* b + ); + +BZ_EXTERN void BZ_API(BZ2_bzReadGetUnused) ( + int* bzerror, + BZFILE* b, + void** unused, + int* nUnused + ); + +BZ_EXTERN int BZ_API(BZ2_bzRead) ( + int* bzerror, + BZFILE* b, + void* buf, + int len + ); + +BZ_EXTERN BZFILE* BZ_API(BZ2_bzWriteOpen) ( + int* bzerror, + FILE* f, + int blockSize100k, + int verbosity, + int workFactor + ); + +BZ_EXTERN void BZ_API(BZ2_bzWrite) ( + int* bzerror, + BZFILE* b, + void* buf, + int len + ); + +BZ_EXTERN void BZ_API(BZ2_bzWriteClose) ( + int* bzerror, + BZFILE* b, + int abandon, + unsigned int* nbytes_in, + unsigned int* nbytes_out + ); + +BZ_EXTERN void BZ_API(BZ2_bzWriteClose64) ( + int* bzerror, + BZFILE* b, + int abandon, + unsigned int* nbytes_in_lo32, + unsigned int* nbytes_in_hi32, + unsigned int* nbytes_out_lo32, + unsigned int* nbytes_out_hi32 + ); +#endif + + +/*-- Utility functions --*/ + +BZ_EXTERN int BZ_API(BZ2_bzBuffToBuffCompress) ( + char* dest, + unsigned int* destLen, + char* source, + unsigned int sourceLen, + int blockSize100k, + int verbosity, + int workFactor + ); + +BZ_EXTERN int BZ_API(BZ2_bzBuffToBuffDecompress) ( + char* dest, + unsigned int* destLen, + char* source, + unsigned int sourceLen, + int small, + int verbosity + ); + + +/*-- + Code contributed by Yoshioka Tsuneo (tsuneo@rr.iij4u.or.jp) + to support better zlib compatibility. + This code is not _officially_ part of libbzip2 (yet); + I haven't tested it, documented it, or considered the + threading-safeness of it. + If this code breaks, please contact both Yoshioka and me. +--*/ + +BZ_EXTERN const char * BZ_API(BZ2_bzlibVersion) ( + void + ); + +#ifndef BZ_NO_STDIO +BZ_EXTERN BZFILE * BZ_API(BZ2_bzopen) ( + const char *path, + const char *mode + ); + +BZ_EXTERN BZFILE * BZ_API(BZ2_bzdopen) ( + int fd, + const char *mode + ); + +BZ_EXTERN int BZ_API(BZ2_bzread) ( + BZFILE* b, + void* buf, + int len + ); + +BZ_EXTERN int BZ_API(BZ2_bzwrite) ( + BZFILE* b, + void* buf, + int len + ); + +BZ_EXTERN int BZ_API(BZ2_bzflush) ( + BZFILE* b + ); + +BZ_EXTERN void BZ_API(BZ2_bzclose) ( + BZFILE* b + ); + +BZ_EXTERN const char * BZ_API(BZ2_bzerror) ( + BZFILE *b, + int *errnum + ); +#endif + +#ifdef __cplusplus +} +#endif + +#endif + +/*-------------------------------------------------------------*/ +/*--- end bzlib.h ---*/ +/*-------------------------------------------------------------*/ diff --git a/src/misc/bzlib/bzlib_private.h b/src/misc/bzlib/bzlib_private.h new file mode 100644 index 00000000..23427879 --- /dev/null +++ b/src/misc/bzlib/bzlib_private.h @@ -0,0 +1,509 @@ + +/*-------------------------------------------------------------*/ +/*--- Private header file for the library. ---*/ +/*--- bzlib_private.h ---*/ +/*-------------------------------------------------------------*/ + +/* ------------------------------------------------------------------ + This file is part of bzip2/libbzip2, a program and library for + lossless, block-sorting data compression. + + bzip2/libbzip2 version 1.0.5 of 10 December 2007 + Copyright (C) 1996-2007 Julian Seward <jseward@bzip.org> + + Please read the WARNING, DISCLAIMER and PATENTS sections in the + README file. + + This program is released under the terms of the license contained + in the file LICENSE. + ------------------------------------------------------------------ */ + + +#ifndef _BZLIB_PRIVATE_H +#define _BZLIB_PRIVATE_H + +#include <stdlib.h> + +#ifndef BZ_NO_STDIO +#include <stdio.h> +#include <ctype.h> +#include <string.h> +#endif + +#include "bzlib.h" + + + +/*-- General stuff. --*/ + +#define BZ_VERSION "1.0.5, 10-Dec-2007" + +typedef char Char; +typedef unsigned char Bool; +typedef unsigned char UChar; +typedef int Int32; +typedef unsigned int UInt32; +typedef short Int16; +typedef unsigned short UInt16; + +#define True ((Bool)1) +#define False ((Bool)0) + +#ifndef __GNUC__ +#define __inline__ /* */ +#endif + +#ifndef BZ_NO_STDIO + +extern void BZ2_bz__AssertH__fail ( int errcode ); +#define AssertH(cond,errcode) \ + { if (!(cond)) BZ2_bz__AssertH__fail ( errcode ); } + +#if BZ_DEBUG +#define AssertD(cond,msg) \ + { if (!(cond)) { \ + fprintf ( stderr, \ + "\n\nlibbzip2(debug build): internal error\n\t%s\n", msg );\ + exit(1); \ + }} +#else +#define AssertD(cond,msg) /* */ +#endif + +#define VPrintf0(zf) \ + fprintf(stderr,zf) +#define VPrintf1(zf,za1) \ + fprintf(stderr,zf,za1) +#define VPrintf2(zf,za1,za2) \ + fprintf(stderr,zf,za1,za2) +#define VPrintf3(zf,za1,za2,za3) \ + fprintf(stderr,zf,za1,za2,za3) +#define VPrintf4(zf,za1,za2,za3,za4) \ + fprintf(stderr,zf,za1,za2,za3,za4) +#define VPrintf5(zf,za1,za2,za3,za4,za5) \ + fprintf(stderr,zf,za1,za2,za3,za4,za5) + +#else + +extern void bz_internal_error ( int errcode ); +#define AssertH(cond,errcode) \ + { if (!(cond)) bz_internal_error ( errcode ); } +#define AssertD(cond,msg) do { } while (0) +#define VPrintf0(zf) do { } while (0) +#define VPrintf1(zf,za1) do { } while (0) +#define VPrintf2(zf,za1,za2) do { } while (0) +#define VPrintf3(zf,za1,za2,za3) do { } while (0) +#define VPrintf4(zf,za1,za2,za3,za4) do { } while (0) +#define VPrintf5(zf,za1,za2,za3,za4,za5) do { } while (0) + +#endif + + +#define BZALLOC(nnn) (strm->bzalloc)(strm->opaque,(nnn),1) +#define BZFREE(ppp) (strm->bzfree)(strm->opaque,(ppp)) + + +/*-- Header bytes. --*/ + +#define BZ_HDR_B 0x42 /* 'B' */ +#define BZ_HDR_Z 0x5a /* 'Z' */ +#define BZ_HDR_h 0x68 /* 'h' */ +#define BZ_HDR_0 0x30 /* '0' */ + +/*-- Constants for the back end. --*/ + +#define BZ_MAX_ALPHA_SIZE 258 +#define BZ_MAX_CODE_LEN 23 + +#define BZ_RUNA 0 +#define BZ_RUNB 1 + +#define BZ_N_GROUPS 6 +#define BZ_G_SIZE 50 +#define BZ_N_ITERS 4 + +#define BZ_MAX_SELECTORS (2 + (900000 / BZ_G_SIZE)) + + + +/*-- Stuff for randomising repetitive blocks. --*/ + +extern Int32 BZ2_rNums[512]; + +#define BZ_RAND_DECLS \ + Int32 rNToGo; \ + Int32 rTPos \ + +#define BZ_RAND_INIT_MASK \ + s->rNToGo = 0; \ + s->rTPos = 0 \ + +#define BZ_RAND_MASK ((s->rNToGo == 1) ? 1 : 0) + +#define BZ_RAND_UPD_MASK \ + if (s->rNToGo == 0) { \ + s->rNToGo = BZ2_rNums[s->rTPos]; \ + s->rTPos++; \ + if (s->rTPos == 512) s->rTPos = 0; \ + } \ + s->rNToGo--; + + + +/*-- Stuff for doing CRCs. --*/ + +extern UInt32 BZ2_crc32Table[256]; + +#define BZ_INITIALISE_CRC(crcVar) \ +{ \ + crcVar = 0xffffffffL; \ +} + +#define BZ_FINALISE_CRC(crcVar) \ +{ \ + crcVar = ~(crcVar); \ +} + +#define BZ_UPDATE_CRC(crcVar,cha) \ +{ \ + crcVar = (crcVar << 8) ^ \ + BZ2_crc32Table[(crcVar >> 24) ^ \ + ((UChar)cha)]; \ +} + + + +/*-- States and modes for compression. --*/ + +#define BZ_M_IDLE 1 +#define BZ_M_RUNNING 2 +#define BZ_M_FLUSHING 3 +#define BZ_M_FINISHING 4 + +#define BZ_S_OUTPUT 1 +#define BZ_S_INPUT 2 + +#define BZ_N_RADIX 2 +#define BZ_N_QSORT 12 +#define BZ_N_SHELL 18 +#define BZ_N_OVERSHOOT (BZ_N_RADIX + BZ_N_QSORT + BZ_N_SHELL + 2) + + + + +/*-- Structure holding all the compression-side stuff. --*/ + +typedef + struct { + /* pointer back to the struct bz_stream */ + bz_stream* strm; + + /* mode this stream is in, and whether inputting */ + /* or outputting data */ + Int32 mode; + Int32 state; + + /* remembers avail_in when flush/finish requested */ + UInt32 avail_in_expect; + + /* for doing the block sorting */ + UInt32* arr1; + UInt32* arr2; + UInt32* ftab; + Int32 origPtr; + + /* aliases for arr1 and arr2 */ + UInt32* ptr; + UChar* block; + UInt16* mtfv; + UChar* zbits; + + /* for deciding when to use the fallback sorting algorithm */ + Int32 workFactor; + + /* run-length-encoding of the input */ + UInt32 state_in_ch; + Int32 state_in_len; + BZ_RAND_DECLS; + + /* input and output limits and current posns */ + Int32 nblock; + Int32 nblockMAX; + Int32 numZ; + Int32 state_out_pos; + + /* map of bytes used in block */ + Int32 nInUse; + Bool inUse[256]; + UChar unseqToSeq[256]; + + /* the buffer for bit stream creation */ + UInt32 bsBuff; + Int32 bsLive; + + /* block and combined CRCs */ + UInt32 blockCRC; + UInt32 combinedCRC; + + /* misc administratium */ + Int32 verbosity; + Int32 blockNo; + Int32 blockSize100k; + + /* stuff for coding the MTF values */ + Int32 nMTF; + Int32 mtfFreq [BZ_MAX_ALPHA_SIZE]; + UChar selector [BZ_MAX_SELECTORS]; + UChar selectorMtf[BZ_MAX_SELECTORS]; + + UChar len [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; + Int32 code [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; + Int32 rfreq [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; + /* second dimension: only 3 needed; 4 makes index calculations faster */ + UInt32 len_pack[BZ_MAX_ALPHA_SIZE][4]; + + } + EState; + + + +/*-- externs for compression. --*/ + +extern void +BZ2_blockSort ( EState* ); + +extern void +BZ2_compressBlock ( EState*, Bool ); + +extern void +BZ2_bsInitWrite ( EState* ); + +extern void +BZ2_hbAssignCodes ( Int32*, UChar*, Int32, Int32, Int32 ); + +extern void +BZ2_hbMakeCodeLengths ( UChar*, Int32*, Int32, Int32 ); + + + +/*-- states for decompression. --*/ + +#define BZ_X_IDLE 1 +#define BZ_X_OUTPUT 2 + +#define BZ_X_MAGIC_1 10 +#define BZ_X_MAGIC_2 11 +#define BZ_X_MAGIC_3 12 +#define BZ_X_MAGIC_4 13 +#define BZ_X_BLKHDR_1 14 +#define BZ_X_BLKHDR_2 15 +#define BZ_X_BLKHDR_3 16 +#define BZ_X_BLKHDR_4 17 +#define BZ_X_BLKHDR_5 18 +#define BZ_X_BLKHDR_6 19 +#define BZ_X_BCRC_1 20 +#define BZ_X_BCRC_2 21 +#define BZ_X_BCRC_3 22 +#define BZ_X_BCRC_4 23 +#define BZ_X_RANDBIT 24 +#define BZ_X_ORIGPTR_1 25 +#define BZ_X_ORIGPTR_2 26 +#define BZ_X_ORIGPTR_3 27 +#define BZ_X_MAPPING_1 28 +#define BZ_X_MAPPING_2 29 +#define BZ_X_SELECTOR_1 30 +#define BZ_X_SELECTOR_2 31 +#define BZ_X_SELECTOR_3 32 +#define BZ_X_CODING_1 33 +#define BZ_X_CODING_2 34 +#define BZ_X_CODING_3 35 +#define BZ_X_MTF_1 36 +#define BZ_X_MTF_2 37 +#define BZ_X_MTF_3 38 +#define BZ_X_MTF_4 39 +#define BZ_X_MTF_5 40 +#define BZ_X_MTF_6 41 +#define BZ_X_ENDHDR_2 42 +#define BZ_X_ENDHDR_3 43 +#define BZ_X_ENDHDR_4 44 +#define BZ_X_ENDHDR_5 45 +#define BZ_X_ENDHDR_6 46 +#define BZ_X_CCRC_1 47 +#define BZ_X_CCRC_2 48 +#define BZ_X_CCRC_3 49 +#define BZ_X_CCRC_4 50 + + + +/*-- Constants for the fast MTF decoder. --*/ + +#define MTFA_SIZE 4096 +#define MTFL_SIZE 16 + + + +/*-- Structure holding all the decompression-side stuff. --*/ + +typedef + struct { + /* pointer back to the struct bz_stream */ + bz_stream* strm; + + /* state indicator for this stream */ + Int32 state; + + /* for doing the final run-length decoding */ + UChar state_out_ch; + Int32 state_out_len; + Bool blockRandomised; + BZ_RAND_DECLS; + + /* the buffer for bit stream reading */ + UInt32 bsBuff; + Int32 bsLive; + + /* misc administratium */ + Int32 blockSize100k; + Bool smallDecompress; + Int32 currBlockNo; + Int32 verbosity; + + /* for undoing the Burrows-Wheeler transform */ + Int32 origPtr; + UInt32 tPos; + Int32 k0; + Int32 unzftab[256]; + Int32 nblock_used; + Int32 cftab[257]; + Int32 cftabCopy[257]; + + /* for undoing the Burrows-Wheeler transform (FAST) */ + UInt32 *tt; + + /* for undoing the Burrows-Wheeler transform (SMALL) */ + UInt16 *ll16; + UChar *ll4; + + /* stored and calculated CRCs */ + UInt32 storedBlockCRC; + UInt32 storedCombinedCRC; + UInt32 calculatedBlockCRC; + UInt32 calculatedCombinedCRC; + + /* map of bytes used in block */ + Int32 nInUse; + Bool inUse[256]; + Bool inUse16[16]; + UChar seqToUnseq[256]; + + /* for decoding the MTF values */ + UChar mtfa [MTFA_SIZE]; + Int32 mtfbase[256 / MTFL_SIZE]; + UChar selector [BZ_MAX_SELECTORS]; + UChar selectorMtf[BZ_MAX_SELECTORS]; + UChar len [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; + + Int32 limit [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; + Int32 base [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; + Int32 perm [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; + Int32 minLens[BZ_N_GROUPS]; + + /* save area for scalars in the main decompress code */ + Int32 save_i; + Int32 save_j; + Int32 save_t; + Int32 save_alphaSize; + Int32 save_nGroups; + Int32 save_nSelectors; + Int32 save_EOB; + Int32 save_groupNo; + Int32 save_groupPos; + Int32 save_nextSym; + Int32 save_nblockMAX; + Int32 save_nblock; + Int32 save_es; + Int32 save_N; + Int32 save_curr; + Int32 save_zt; + Int32 save_zn; + Int32 save_zvec; + Int32 save_zj; + Int32 save_gSel; + Int32 save_gMinlen; + Int32* save_gLimit; + Int32* save_gBase; + Int32* save_gPerm; + + } + DState; + + + +/*-- Macros for decompression. --*/ + +#define BZ_GET_FAST(cccc) \ + /* c_tPos is unsigned, hence test < 0 is pointless. */ \ + if (s->tPos >= (UInt32)100000 * (UInt32)s->blockSize100k) return True; \ + s->tPos = s->tt[s->tPos]; \ + cccc = (UChar)(s->tPos & 0xff); \ + s->tPos >>= 8; + +#define BZ_GET_FAST_C(cccc) \ + /* c_tPos is unsigned, hence test < 0 is pointless. */ \ + if (c_tPos >= (UInt32)100000 * (UInt32)ro_blockSize100k) return True; \ + c_tPos = c_tt[c_tPos]; \ + cccc = (UChar)(c_tPos & 0xff); \ + c_tPos >>= 8; + +#define SET_LL4(i,n) \ + { if (((i) & 0x1) == 0) \ + s->ll4[(i) >> 1] = (s->ll4[(i) >> 1] & 0xf0) | (n); else \ + s->ll4[(i) >> 1] = (s->ll4[(i) >> 1] & 0x0f) | ((n) << 4); \ + } + +#define GET_LL4(i) \ + ((((UInt32)(s->ll4[(i) >> 1])) >> (((i) << 2) & 0x4)) & 0xF) + +#define SET_LL(i,n) \ + { s->ll16[i] = (UInt16)(n & 0x0000ffff); \ + SET_LL4(i, n >> 16); \ + } + +#define GET_LL(i) \ + (((UInt32)s->ll16[i]) | (GET_LL4(i) << 16)) + +#define BZ_GET_SMALL(cccc) \ + /* c_tPos is unsigned, hence test < 0 is pointless. */ \ + if (s->tPos >= (UInt32)100000 * (UInt32)s->blockSize100k) return True; \ + cccc = BZ2_indexIntoF ( s->tPos, s->cftab ); \ + s->tPos = GET_LL(s->tPos); + + +/*-- externs for decompression. --*/ + +extern Int32 +BZ2_indexIntoF ( Int32, Int32* ); + +extern Int32 +BZ2_decompress ( DState* ); + +extern void +BZ2_hbCreateDecodeTables ( Int32*, Int32*, Int32*, UChar*, + Int32, Int32, Int32 ); + + +#endif + + +/*-- BZ_NO_STDIO seems to make NULL disappear on some platforms. --*/ + +#ifdef BZ_NO_STDIO +#ifndef NULL +#define NULL 0 +#endif +#endif + + +/*-------------------------------------------------------------*/ +/*--- end bzlib_private.h ---*/ +/*-------------------------------------------------------------*/ diff --git a/src/misc/bzlib/compress.c b/src/misc/bzlib/compress.c new file mode 100644 index 00000000..7d9b3da7 --- /dev/null +++ b/src/misc/bzlib/compress.c @@ -0,0 +1,672 @@ + +/*-------------------------------------------------------------*/ +/*--- Compression machinery (not incl block sorting) ---*/ +/*--- compress.c ---*/ +/*-------------------------------------------------------------*/ + +/* ------------------------------------------------------------------ + This file is part of bzip2/libbzip2, a program and library for + lossless, block-sorting data compression. + + bzip2/libbzip2 version 1.0.5 of 10 December 2007 + Copyright (C) 1996-2007 Julian Seward <jseward@bzip.org> + + Please read the WARNING, DISCLAIMER and PATENTS sections in the + README file. + + This program is released under the terms of the license contained + in the file LICENSE. + ------------------------------------------------------------------ */ + + +/* CHANGES + 0.9.0 -- original version. + 0.9.0a/b -- no changes in this file. + 0.9.0c -- changed setting of nGroups in sendMTFValues() + so as to do a bit better on small files +*/ + +#include "bzlib_private.h" + + +/*---------------------------------------------------*/ +/*--- Bit stream I/O ---*/ +/*---------------------------------------------------*/ + +/*---------------------------------------------------*/ +void BZ2_bsInitWrite ( EState* s ) +{ + s->bsLive = 0; + s->bsBuff = 0; +} + + +/*---------------------------------------------------*/ +static +void bsFinishWrite ( EState* s ) +{ + while (s->bsLive > 0) { + s->zbits[s->numZ] = (UChar)(s->bsBuff >> 24); + s->numZ++; + s->bsBuff <<= 8; + s->bsLive -= 8; + } +} + + +/*---------------------------------------------------*/ +#define bsNEEDW(nz) \ +{ \ + while (s->bsLive >= 8) { \ + s->zbits[s->numZ] \ + = (UChar)(s->bsBuff >> 24); \ + s->numZ++; \ + s->bsBuff <<= 8; \ + s->bsLive -= 8; \ + } \ +} + + +/*---------------------------------------------------*/ +static +__inline__ +void bsW ( EState* s, Int32 n, UInt32 v ) +{ + bsNEEDW ( n ); + s->bsBuff |= (v << (32 - s->bsLive - n)); + s->bsLive += n; +} + + +/*---------------------------------------------------*/ +static +void bsPutUInt32 ( EState* s, UInt32 u ) +{ + bsW ( s, 8, (u >> 24) & 0xffL ); + bsW ( s, 8, (u >> 16) & 0xffL ); + bsW ( s, 8, (u >> 8) & 0xffL ); + bsW ( s, 8, u & 0xffL ); +} + + +/*---------------------------------------------------*/ +static +void bsPutUChar ( EState* s, UChar c ) +{ + bsW( s, 8, (UInt32)c ); +} + + +/*---------------------------------------------------*/ +/*--- The back end proper ---*/ +/*---------------------------------------------------*/ + +/*---------------------------------------------------*/ +static +void makeMaps_e ( EState* s ) +{ + Int32 i; + s->nInUse = 0; + for (i = 0; i < 256; i++) + if (s->inUse[i]) { + s->unseqToSeq[i] = s->nInUse; + s->nInUse++; + } +} + + +/*---------------------------------------------------*/ +static +void generateMTFValues ( EState* s ) +{ + UChar yy[256]; + Int32 i, j; + Int32 zPend; + Int32 wr; + Int32 EOB; + + /* + After sorting (eg, here), + s->arr1 [ 0 .. s->nblock-1 ] holds sorted order, + and + ((UChar*)s->arr2) [ 0 .. s->nblock-1 ] + holds the original block data. + + The first thing to do is generate the MTF values, + and put them in + ((UInt16*)s->arr1) [ 0 .. s->nblock-1 ]. + Because there are strictly fewer or equal MTF values + than block values, ptr values in this area are overwritten + with MTF values only when they are no longer needed. + + The final compressed bitstream is generated into the + area starting at + (UChar*) (&((UChar*)s->arr2)[s->nblock]) + + These storage aliases are set up in bzCompressInit(), + except for the last one, which is arranged in + compressBlock(). + */ + UInt32* ptr = s->ptr; + UChar* block = s->block; + UInt16* mtfv = s->mtfv; + + makeMaps_e ( s ); + EOB = s->nInUse+1; + + for (i = 0; i <= EOB; i++) s->mtfFreq[i] = 0; + + wr = 0; + zPend = 0; + for (i = 0; i < s->nInUse; i++) yy[i] = (UChar) i; + + for (i = 0; i < s->nblock; i++) { + UChar ll_i; + AssertD ( wr <= i, "generateMTFValues(1)" ); + j = ptr[i]-1; if (j < 0) j += s->nblock; + ll_i = s->unseqToSeq[block[j]]; + AssertD ( ll_i < s->nInUse, "generateMTFValues(2a)" ); + + if (yy[0] == ll_i) { + zPend++; + } else { + + if (zPend > 0) { + zPend--; + while (True) { + if (zPend & 1) { + mtfv[wr] = BZ_RUNB; wr++; + s->mtfFreq[BZ_RUNB]++; + } else { + mtfv[wr] = BZ_RUNA; wr++; + s->mtfFreq[BZ_RUNA]++; + } + if (zPend < 2) break; + zPend = (zPend - 2) / 2; + }; + zPend = 0; + } + { + register UChar rtmp; + register UChar* ryy_j; + register UChar rll_i; + rtmp = yy[1]; + yy[1] = yy[0]; + ryy_j = &(yy[1]); + rll_i = ll_i; + while ( rll_i != rtmp ) { + register UChar rtmp2; + ryy_j++; + rtmp2 = rtmp; + rtmp = *ryy_j; + *ryy_j = rtmp2; + }; + yy[0] = rtmp; + j = ryy_j - &(yy[0]); + mtfv[wr] = j+1; wr++; s->mtfFreq[j+1]++; + } + + } + } + + if (zPend > 0) { + zPend--; + while (True) { + if (zPend & 1) { + mtfv[wr] = BZ_RUNB; wr++; + s->mtfFreq[BZ_RUNB]++; + } else { + mtfv[wr] = BZ_RUNA; wr++; + s->mtfFreq[BZ_RUNA]++; + } + if (zPend < 2) break; + zPend = (zPend - 2) / 2; + }; + zPend = 0; + } + + mtfv[wr] = EOB; wr++; s->mtfFreq[EOB]++; + + s->nMTF = wr; +} + + +/*---------------------------------------------------*/ +#define BZ_LESSER_ICOST 0 +#define BZ_GREATER_ICOST 15 + +static +void sendMTFValues ( EState* s ) +{ + Int32 v, t, i, j, gs, ge, totc, bt, bc, iter; + Int32 nSelectors, alphaSize, minLen, maxLen, selCtr; + Int32 nGroups, nBytes; + + /*-- + UChar len [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; + is a global since the decoder also needs it. + + Int32 code[BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; + Int32 rfreq[BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; + are also globals only used in this proc. + Made global to keep stack frame size small. + --*/ + + + UInt16 cost[BZ_N_GROUPS]; + Int32 fave[BZ_N_GROUPS]; + + UInt16* mtfv = s->mtfv; + + if (s->verbosity >= 3) + VPrintf3( " %d in block, %d after MTF & 1-2 coding, " + "%d+2 syms in use\n", + s->nblock, s->nMTF, s->nInUse ); + + alphaSize = s->nInUse+2; + for (t = 0; t < BZ_N_GROUPS; t++) + for (v = 0; v < alphaSize; v++) + s->len[t][v] = BZ_GREATER_ICOST; + + /*--- Decide how many coding tables to use ---*/ + AssertH ( s->nMTF > 0, 3001 ); + if (s->nMTF < 200) nGroups = 2; else + if (s->nMTF < 600) nGroups = 3; else + if (s->nMTF < 1200) nGroups = 4; else + if (s->nMTF < 2400) nGroups = 5; else + nGroups = 6; + + /*--- Generate an initial set of coding tables ---*/ + { + Int32 nPart, remF, tFreq, aFreq; + + nPart = nGroups; + remF = s->nMTF; + gs = 0; + while (nPart > 0) { + tFreq = remF / nPart; + ge = gs-1; + aFreq = 0; + while (aFreq < tFreq && ge < alphaSize-1) { + ge++; + aFreq += s->mtfFreq[ge]; + } + + if (ge > gs + && nPart != nGroups && nPart != 1 + && ((nGroups-nPart) % 2 == 1)) { + aFreq -= s->mtfFreq[ge]; + ge--; + } + + if (s->verbosity >= 3) + VPrintf5( " initial group %d, [%d .. %d], " + "has %d syms (%4.1f%%)\n", + nPart, gs, ge, aFreq, + (100.0 * (float)aFreq) / (float)(s->nMTF) ); + + for (v = 0; v < alphaSize; v++) + if (v >= gs && v <= ge) + s->len[nPart-1][v] = BZ_LESSER_ICOST; else + s->len[nPart-1][v] = BZ_GREATER_ICOST; + + nPart--; + gs = ge+1; + remF -= aFreq; + } + } + + /*--- + Iterate up to BZ_N_ITERS times to improve the tables. + ---*/ + for (iter = 0; iter < BZ_N_ITERS; iter++) { + + for (t = 0; t < nGroups; t++) fave[t] = 0; + + for (t = 0; t < nGroups; t++) + for (v = 0; v < alphaSize; v++) + s->rfreq[t][v] = 0; + + /*--- + Set up an auxiliary length table which is used to fast-track + the common case (nGroups == 6). + ---*/ + if (nGroups == 6) { + for (v = 0; v < alphaSize; v++) { + s->len_pack[v][0] = (s->len[1][v] << 16) | s->len[0][v]; + s->len_pack[v][1] = (s->len[3][v] << 16) | s->len[2][v]; + s->len_pack[v][2] = (s->len[5][v] << 16) | s->len[4][v]; + } + } + + nSelectors = 0; + totc = 0; + gs = 0; + while (True) { + + /*--- Set group start & end marks. --*/ + if (gs >= s->nMTF) break; + ge = gs + BZ_G_SIZE - 1; + if (ge >= s->nMTF) ge = s->nMTF-1; + + /*-- + Calculate the cost of this group as coded + by each of the coding tables. + --*/ + for (t = 0; t < nGroups; t++) cost[t] = 0; + + if (nGroups == 6 && 50 == ge-gs+1) { + /*--- fast track the common case ---*/ + register UInt32 cost01, cost23, cost45; + register UInt16 icv; + cost01 = cost23 = cost45 = 0; + +# define BZ_ITER(nn) \ + icv = mtfv[gs+(nn)]; \ + cost01 += s->len_pack[icv][0]; \ + cost23 += s->len_pack[icv][1]; \ + cost45 += s->len_pack[icv][2]; \ + + BZ_ITER(0); BZ_ITER(1); BZ_ITER(2); BZ_ITER(3); BZ_ITER(4); + BZ_ITER(5); BZ_ITER(6); BZ_ITER(7); BZ_ITER(8); BZ_ITER(9); + BZ_ITER(10); BZ_ITER(11); BZ_ITER(12); BZ_ITER(13); BZ_ITER(14); + BZ_ITER(15); BZ_ITER(16); BZ_ITER(17); BZ_ITER(18); BZ_ITER(19); + BZ_ITER(20); BZ_ITER(21); BZ_ITER(22); BZ_ITER(23); BZ_ITER(24); + BZ_ITER(25); BZ_ITER(26); BZ_ITER(27); BZ_ITER(28); BZ_ITER(29); + BZ_ITER(30); BZ_ITER(31); BZ_ITER(32); BZ_ITER(33); BZ_ITER(34); + BZ_ITER(35); BZ_ITER(36); BZ_ITER(37); BZ_ITER(38); BZ_ITER(39); + BZ_ITER(40); BZ_ITER(41); BZ_ITER(42); BZ_ITER(43); BZ_ITER(44); + BZ_ITER(45); BZ_ITER(46); BZ_ITER(47); BZ_ITER(48); BZ_ITER(49); + +# undef BZ_ITER + + cost[0] = cost01 & 0xffff; cost[1] = cost01 >> 16; + cost[2] = cost23 & 0xffff; cost[3] = cost23 >> 16; + cost[4] = cost45 & 0xffff; cost[5] = cost45 >> 16; + + } else { + /*--- slow version which correctly handles all situations ---*/ + for (i = gs; i <= ge; i++) { + UInt16 icv = mtfv[i]; + for (t = 0; t < nGroups; t++) cost[t] += s->len[t][icv]; + } + } + + /*-- + Find the coding table which is best for this group, + and record its identity in the selector table. + --*/ + bc = 999999999; bt = -1; + for (t = 0; t < nGroups; t++) + if (cost[t] < bc) { bc = cost[t]; bt = t; }; + totc += bc; + fave[bt]++; + s->selector[nSelectors] = bt; + nSelectors++; + + /*-- + Increment the symbol frequencies for the selected table. + --*/ + if (nGroups == 6 && 50 == ge-gs+1) { + /*--- fast track the common case ---*/ + +# define BZ_ITUR(nn) s->rfreq[bt][ mtfv[gs+(nn)] ]++ + + BZ_ITUR(0); BZ_ITUR(1); BZ_ITUR(2); BZ_ITUR(3); BZ_ITUR(4); + BZ_ITUR(5); BZ_ITUR(6); BZ_ITUR(7); BZ_ITUR(8); BZ_ITUR(9); + BZ_ITUR(10); BZ_ITUR(11); BZ_ITUR(12); BZ_ITUR(13); BZ_ITUR(14); + BZ_ITUR(15); BZ_ITUR(16); BZ_ITUR(17); BZ_ITUR(18); BZ_ITUR(19); + BZ_ITUR(20); BZ_ITUR(21); BZ_ITUR(22); BZ_ITUR(23); BZ_ITUR(24); + BZ_ITUR(25); BZ_ITUR(26); BZ_ITUR(27); BZ_ITUR(28); BZ_ITUR(29); + BZ_ITUR(30); BZ_ITUR(31); BZ_ITUR(32); BZ_ITUR(33); BZ_ITUR(34); + BZ_ITUR(35); BZ_ITUR(36); BZ_ITUR(37); BZ_ITUR(38); BZ_ITUR(39); + BZ_ITUR(40); BZ_ITUR(41); BZ_ITUR(42); BZ_ITUR(43); BZ_ITUR(44); + BZ_ITUR(45); BZ_ITUR(46); BZ_ITUR(47); BZ_ITUR(48); BZ_ITUR(49); + +# undef BZ_ITUR + + } else { + /*--- slow version which correctly handles all situations ---*/ + for (i = gs; i <= ge; i++) + s->rfreq[bt][ mtfv[i] ]++; + } + + gs = ge+1; + } + if (s->verbosity >= 3) { + VPrintf2 ( " pass %d: size is %d, grp uses are ", + iter+1, totc/8 ); + for (t = 0; t < nGroups; t++) + VPrintf1 ( "%d ", fave[t] ); + VPrintf0 ( "\n" ); + } + + /*-- + Recompute the tables based on the accumulated frequencies. + --*/ + /* maxLen was changed from 20 to 17 in bzip2-1.0.3. See + comment in huffman.c for details. */ + for (t = 0; t < nGroups; t++) + BZ2_hbMakeCodeLengths ( &(s->len[t][0]), &(s->rfreq[t][0]), + alphaSize, 17 /*20*/ ); + } + + + AssertH( nGroups < 8, 3002 ); + AssertH( nSelectors < 32768 && + nSelectors <= (2 + (900000 / BZ_G_SIZE)), + 3003 ); + + + /*--- Compute MTF values for the selectors. ---*/ + { + UChar pos[BZ_N_GROUPS], ll_i, tmp2, tmp; + for (i = 0; i < nGroups; i++) pos[i] = i; + for (i = 0; i < nSelectors; i++) { + ll_i = s->selector[i]; + j = 0; + tmp = pos[j]; + while ( ll_i != tmp ) { + j++; + tmp2 = tmp; + tmp = pos[j]; + pos[j] = tmp2; + }; + pos[0] = tmp; + s->selectorMtf[i] = j; + } + }; + + /*--- Assign actual codes for the tables. --*/ + for (t = 0; t < nGroups; t++) { + minLen = 32; + maxLen = 0; + for (i = 0; i < alphaSize; i++) { + if (s->len[t][i] > maxLen) maxLen = s->len[t][i]; + if (s->len[t][i] < minLen) minLen = s->len[t][i]; + } + AssertH ( !(maxLen > 17 /*20*/ ), 3004 ); + AssertH ( !(minLen < 1), 3005 ); + BZ2_hbAssignCodes ( &(s->code[t][0]), &(s->len[t][0]), + minLen, maxLen, alphaSize ); + } + + /*--- Transmit the mapping table. ---*/ + { + Bool inUse16[16]; + for (i = 0; i < 16; i++) { + inUse16[i] = False; + for (j = 0; j < 16; j++) + if (s->inUse[i * 16 + j]) inUse16[i] = True; + } + + nBytes = s->numZ; + for (i = 0; i < 16; i++) + if (inUse16[i]) bsW(s,1,1); else bsW(s,1,0); + + for (i = 0; i < 16; i++) + if (inUse16[i]) + for (j = 0; j < 16; j++) { + if (s->inUse[i * 16 + j]) bsW(s,1,1); else bsW(s,1,0); + } + + if (s->verbosity >= 3) + VPrintf1( " bytes: mapping %d, ", s->numZ-nBytes ); + } + + /*--- Now the selectors. ---*/ + nBytes = s->numZ; + bsW ( s, 3, nGroups ); + bsW ( s, 15, nSelectors ); + for (i = 0; i < nSelectors; i++) { + for (j = 0; j < s->selectorMtf[i]; j++) bsW(s,1,1); + bsW(s,1,0); + } + if (s->verbosity >= 3) + VPrintf1( "selectors %d, ", s->numZ-nBytes ); + + /*--- Now the coding tables. ---*/ + nBytes = s->numZ; + + for (t = 0; t < nGroups; t++) { + Int32 curr = s->len[t][0]; + bsW ( s, 5, curr ); + for (i = 0; i < alphaSize; i++) { + while (curr < s->len[t][i]) { bsW(s,2,2); curr++; /* 10 */ }; + while (curr > s->len[t][i]) { bsW(s,2,3); curr--; /* 11 */ }; + bsW ( s, 1, 0 ); + } + } + + if (s->verbosity >= 3) + VPrintf1 ( "code lengths %d, ", s->numZ-nBytes ); + + /*--- And finally, the block data proper ---*/ + nBytes = s->numZ; + selCtr = 0; + gs = 0; + while (True) { + if (gs >= s->nMTF) break; + ge = gs + BZ_G_SIZE - 1; + if (ge >= s->nMTF) ge = s->nMTF-1; + AssertH ( s->selector[selCtr] < nGroups, 3006 ); + + if (nGroups == 6 && 50 == ge-gs+1) { + /*--- fast track the common case ---*/ + UInt16 mtfv_i; + UChar* s_len_sel_selCtr + = &(s->len[s->selector[selCtr]][0]); + Int32* s_code_sel_selCtr + = &(s->code[s->selector[selCtr]][0]); + +# define BZ_ITAH(nn) \ + mtfv_i = mtfv[gs+(nn)]; \ + bsW ( s, \ + s_len_sel_selCtr[mtfv_i], \ + s_code_sel_selCtr[mtfv_i] ) + + BZ_ITAH(0); BZ_ITAH(1); BZ_ITAH(2); BZ_ITAH(3); BZ_ITAH(4); + BZ_ITAH(5); BZ_ITAH(6); BZ_ITAH(7); BZ_ITAH(8); BZ_ITAH(9); + BZ_ITAH(10); BZ_ITAH(11); BZ_ITAH(12); BZ_ITAH(13); BZ_ITAH(14); + BZ_ITAH(15); BZ_ITAH(16); BZ_ITAH(17); BZ_ITAH(18); BZ_ITAH(19); + BZ_ITAH(20); BZ_ITAH(21); BZ_ITAH(22); BZ_ITAH(23); BZ_ITAH(24); + BZ_ITAH(25); BZ_ITAH(26); BZ_ITAH(27); BZ_ITAH(28); BZ_ITAH(29); + BZ_ITAH(30); BZ_ITAH(31); BZ_ITAH(32); BZ_ITAH(33); BZ_ITAH(34); + BZ_ITAH(35); BZ_ITAH(36); BZ_ITAH(37); BZ_ITAH(38); BZ_ITAH(39); + BZ_ITAH(40); BZ_ITAH(41); BZ_ITAH(42); BZ_ITAH(43); BZ_ITAH(44); + BZ_ITAH(45); BZ_ITAH(46); BZ_ITAH(47); BZ_ITAH(48); BZ_ITAH(49); + +# undef BZ_ITAH + + } else { + /*--- slow version which correctly handles all situations ---*/ + for (i = gs; i <= ge; i++) { + bsW ( s, + s->len [s->selector[selCtr]] [mtfv[i]], + s->code [s->selector[selCtr]] [mtfv[i]] ); + } + } + + + gs = ge+1; + selCtr++; + } + AssertH( selCtr == nSelectors, 3007 ); + + if (s->verbosity >= 3) + VPrintf1( "codes %d\n", s->numZ-nBytes ); +} + + +/*---------------------------------------------------*/ +void BZ2_compressBlock ( EState* s, Bool is_last_block ) +{ + if (s->nblock > 0) { + + BZ_FINALISE_CRC ( s->blockCRC ); + s->combinedCRC = (s->combinedCRC << 1) | (s->combinedCRC >> 31); + s->combinedCRC ^= s->blockCRC; + if (s->blockNo > 1) s->numZ = 0; + + if (s->verbosity >= 2) + VPrintf4( " block %d: crc = 0x%08x, " + "combined CRC = 0x%08x, size = %d\n", + s->blockNo, s->blockCRC, s->combinedCRC, s->nblock ); + + BZ2_blockSort ( s ); + } + + s->zbits = (UChar*) (&((UChar*)s->arr2)[s->nblock]); + + /*-- If this is the first block, create the stream header. --*/ + if (s->blockNo == 1) { + BZ2_bsInitWrite ( s ); + bsPutUChar ( s, BZ_HDR_B ); + bsPutUChar ( s, BZ_HDR_Z ); + bsPutUChar ( s, BZ_HDR_h ); + bsPutUChar ( s, (UChar)(BZ_HDR_0 + s->blockSize100k) ); + } + + if (s->nblock > 0) { + + bsPutUChar ( s, 0x31 ); bsPutUChar ( s, 0x41 ); + bsPutUChar ( s, 0x59 ); bsPutUChar ( s, 0x26 ); + bsPutUChar ( s, 0x53 ); bsPutUChar ( s, 0x59 ); + + /*-- Now the block's CRC, so it is in a known place. --*/ + bsPutUInt32 ( s, s->blockCRC ); + + /*-- + Now a single bit indicating (non-)randomisation. + As of version 0.9.5, we use a better sorting algorithm + which makes randomisation unnecessary. So always set + the randomised bit to 'no'. Of course, the decoder + still needs to be able to handle randomised blocks + so as to maintain backwards compatibility with + older versions of bzip2. + --*/ + bsW(s,1,0); + + bsW ( s, 24, s->origPtr ); + generateMTFValues ( s ); + sendMTFValues ( s ); + } + + + /*-- If this is the last block, add the stream trailer. --*/ + if (is_last_block) { + + bsPutUChar ( s, 0x17 ); bsPutUChar ( s, 0x72 ); + bsPutUChar ( s, 0x45 ); bsPutUChar ( s, 0x38 ); + bsPutUChar ( s, 0x50 ); bsPutUChar ( s, 0x90 ); + bsPutUInt32 ( s, s->combinedCRC ); + if (s->verbosity >= 2) + VPrintf1( " final combined CRC = 0x%08x\n ", s->combinedCRC ); + bsFinishWrite ( s ); + } +} + + +/*-------------------------------------------------------------*/ +/*--- end compress.c ---*/ +/*-------------------------------------------------------------*/ diff --git a/src/misc/bzlib/crctable.c b/src/misc/bzlib/crctable.c new file mode 100644 index 00000000..215687b2 --- /dev/null +++ b/src/misc/bzlib/crctable.c @@ -0,0 +1,104 @@ + +/*-------------------------------------------------------------*/ +/*--- Table for doing CRCs ---*/ +/*--- crctable.c ---*/ +/*-------------------------------------------------------------*/ + +/* ------------------------------------------------------------------ + This file is part of bzip2/libbzip2, a program and library for + lossless, block-sorting data compression. + + bzip2/libbzip2 version 1.0.5 of 10 December 2007 + Copyright (C) 1996-2007 Julian Seward <jseward@bzip.org> + + Please read the WARNING, DISCLAIMER and PATENTS sections in the + README file. + + This program is released under the terms of the license contained + in the file LICENSE. + ------------------------------------------------------------------ */ + + +#include "bzlib_private.h" + +/*-- + I think this is an implementation of the AUTODIN-II, + Ethernet & FDDI 32-bit CRC standard. Vaguely derived + from code by Rob Warnock, in Section 51 of the + comp.compression FAQ. +--*/ + +UInt32 BZ2_crc32Table[256] = { + + /*-- Ugly, innit? --*/ + + 0x00000000L, 0x04c11db7L, 0x09823b6eL, 0x0d4326d9L, + 0x130476dcL, 0x17c56b6bL, 0x1a864db2L, 0x1e475005L, + 0x2608edb8L, 0x22c9f00fL, 0x2f8ad6d6L, 0x2b4bcb61L, + 0x350c9b64L, 0x31cd86d3L, 0x3c8ea00aL, 0x384fbdbdL, + 0x4c11db70L, 0x48d0c6c7L, 0x4593e01eL, 0x4152fda9L, + 0x5f15adacL, 0x5bd4b01bL, 0x569796c2L, 0x52568b75L, + 0x6a1936c8L, 0x6ed82b7fL, 0x639b0da6L, 0x675a1011L, + 0x791d4014L, 0x7ddc5da3L, 0x709f7b7aL, 0x745e66cdL, + 0x9823b6e0L, 0x9ce2ab57L, 0x91a18d8eL, 0x95609039L, + 0x8b27c03cL, 0x8fe6dd8bL, 0x82a5fb52L, 0x8664e6e5L, + 0xbe2b5b58L, 0xbaea46efL, 0xb7a96036L, 0xb3687d81L, + 0xad2f2d84L, 0xa9ee3033L, 0xa4ad16eaL, 0xa06c0b5dL, + 0xd4326d90L, 0xd0f37027L, 0xddb056feL, 0xd9714b49L, + 0xc7361b4cL, 0xc3f706fbL, 0xceb42022L, 0xca753d95L, + 0xf23a8028L, 0xf6fb9d9fL, 0xfbb8bb46L, 0xff79a6f1L, + 0xe13ef6f4L, 0xe5ffeb43L, 0xe8bccd9aL, 0xec7dd02dL, + 0x34867077L, 0x30476dc0L, 0x3d044b19L, 0x39c556aeL, + 0x278206abL, 0x23431b1cL, 0x2e003dc5L, 0x2ac12072L, + 0x128e9dcfL, 0x164f8078L, 0x1b0ca6a1L, 0x1fcdbb16L, + 0x018aeb13L, 0x054bf6a4L, 0x0808d07dL, 0x0cc9cdcaL, + 0x7897ab07L, 0x7c56b6b0L, 0x71159069L, 0x75d48ddeL, + 0x6b93dddbL, 0x6f52c06cL, 0x6211e6b5L, 0x66d0fb02L, + 0x5e9f46bfL, 0x5a5e5b08L, 0x571d7dd1L, 0x53dc6066L, + 0x4d9b3063L, 0x495a2dd4L, 0x44190b0dL, 0x40d816baL, + 0xaca5c697L, 0xa864db20L, 0xa527fdf9L, 0xa1e6e04eL, + 0xbfa1b04bL, 0xbb60adfcL, 0xb6238b25L, 0xb2e29692L, + 0x8aad2b2fL, 0x8e6c3698L, 0x832f1041L, 0x87ee0df6L, + 0x99a95df3L, 0x9d684044L, 0x902b669dL, 0x94ea7b2aL, + 0xe0b41de7L, 0xe4750050L, 0xe9362689L, 0xedf73b3eL, + 0xf3b06b3bL, 0xf771768cL, 0xfa325055L, 0xfef34de2L, + 0xc6bcf05fL, 0xc27dede8L, 0xcf3ecb31L, 0xcbffd686L, + 0xd5b88683L, 0xd1799b34L, 0xdc3abdedL, 0xd8fba05aL, + 0x690ce0eeL, 0x6dcdfd59L, 0x608edb80L, 0x644fc637L, + 0x7a089632L, 0x7ec98b85L, 0x738aad5cL, 0x774bb0ebL, + 0x4f040d56L, 0x4bc510e1L, 0x46863638L, 0x42472b8fL, + 0x5c007b8aL, 0x58c1663dL, 0x558240e4L, 0x51435d53L, + 0x251d3b9eL, 0x21dc2629L, 0x2c9f00f0L, 0x285e1d47L, + 0x36194d42L, 0x32d850f5L, 0x3f9b762cL, 0x3b5a6b9bL, + 0x0315d626L, 0x07d4cb91L, 0x0a97ed48L, 0x0e56f0ffL, + 0x1011a0faL, 0x14d0bd4dL, 0x19939b94L, 0x1d528623L, + 0xf12f560eL, 0xf5ee4bb9L, 0xf8ad6d60L, 0xfc6c70d7L, + 0xe22b20d2L, 0xe6ea3d65L, 0xeba91bbcL, 0xef68060bL, + 0xd727bbb6L, 0xd3e6a601L, 0xdea580d8L, 0xda649d6fL, + 0xc423cd6aL, 0xc0e2d0ddL, 0xcda1f604L, 0xc960ebb3L, + 0xbd3e8d7eL, 0xb9ff90c9L, 0xb4bcb610L, 0xb07daba7L, + 0xae3afba2L, 0xaafbe615L, 0xa7b8c0ccL, 0xa379dd7bL, + 0x9b3660c6L, 0x9ff77d71L, 0x92b45ba8L, 0x9675461fL, + 0x8832161aL, 0x8cf30badL, 0x81b02d74L, 0x857130c3L, + 0x5d8a9099L, 0x594b8d2eL, 0x5408abf7L, 0x50c9b640L, + 0x4e8ee645L, 0x4a4ffbf2L, 0x470cdd2bL, 0x43cdc09cL, + 0x7b827d21L, 0x7f436096L, 0x7200464fL, 0x76c15bf8L, + 0x68860bfdL, 0x6c47164aL, 0x61043093L, 0x65c52d24L, + 0x119b4be9L, 0x155a565eL, 0x18197087L, 0x1cd86d30L, + 0x029f3d35L, 0x065e2082L, 0x0b1d065bL, 0x0fdc1becL, + 0x3793a651L, 0x3352bbe6L, 0x3e119d3fL, 0x3ad08088L, + 0x2497d08dL, 0x2056cd3aL, 0x2d15ebe3L, 0x29d4f654L, + 0xc5a92679L, 0xc1683bceL, 0xcc2b1d17L, 0xc8ea00a0L, + 0xd6ad50a5L, 0xd26c4d12L, 0xdf2f6bcbL, 0xdbee767cL, + 0xe3a1cbc1L, 0xe760d676L, 0xea23f0afL, 0xeee2ed18L, + 0xf0a5bd1dL, 0xf464a0aaL, 0xf9278673L, 0xfde69bc4L, + 0x89b8fd09L, 0x8d79e0beL, 0x803ac667L, 0x84fbdbd0L, + 0x9abc8bd5L, 0x9e7d9662L, 0x933eb0bbL, 0x97ffad0cL, + 0xafb010b1L, 0xab710d06L, 0xa6322bdfL, 0xa2f33668L, + 0xbcb4666dL, 0xb8757bdaL, 0xb5365d03L, 0xb1f740b4L +}; + + +/*-------------------------------------------------------------*/ +/*--- end crctable.c ---*/ +/*-------------------------------------------------------------*/ diff --git a/src/misc/bzlib/decompress.c b/src/misc/bzlib/decompress.c new file mode 100644 index 00000000..bba5e0fa --- /dev/null +++ b/src/misc/bzlib/decompress.c @@ -0,0 +1,626 @@ + +/*-------------------------------------------------------------*/ +/*--- Decompression machinery ---*/ +/*--- decompress.c ---*/ +/*-------------------------------------------------------------*/ + +/* ------------------------------------------------------------------ + This file is part of bzip2/libbzip2, a program and library for + lossless, block-sorting data compression. + + bzip2/libbzip2 version 1.0.5 of 10 December 2007 + Copyright (C) 1996-2007 Julian Seward <jseward@bzip.org> + + Please read the WARNING, DISCLAIMER and PATENTS sections in the + README file. + + This program is released under the terms of the license contained + in the file LICENSE. + ------------------------------------------------------------------ */ + + +#include "bzlib_private.h" + + +/*---------------------------------------------------*/ +static +void makeMaps_d ( DState* s ) +{ + Int32 i; + s->nInUse = 0; + for (i = 0; i < 256; i++) + if (s->inUse[i]) { + s->seqToUnseq[s->nInUse] = i; + s->nInUse++; + } +} + + +/*---------------------------------------------------*/ +#define RETURN(rrr) \ + { retVal = rrr; goto save_state_and_return; }; + +#define GET_BITS(lll,vvv,nnn) \ + case lll: s->state = lll; \ + while (True) { \ + if (s->bsLive >= nnn) { \ + UInt32 v; \ + v = (s->bsBuff >> \ + (s->bsLive-nnn)) & ((1 << nnn)-1); \ + s->bsLive -= nnn; \ + vvv = v; \ + break; \ + } \ + if (s->strm->avail_in == 0) RETURN(BZ_OK); \ + s->bsBuff \ + = (s->bsBuff << 8) | \ + ((UInt32) \ + (*((UChar*)(s->strm->next_in)))); \ + s->bsLive += 8; \ + s->strm->next_in++; \ + s->strm->avail_in--; \ + s->strm->total_in_lo32++; \ + if (s->strm->total_in_lo32 == 0) \ + s->strm->total_in_hi32++; \ + } + +#define GET_UCHAR(lll,uuu) \ + GET_BITS(lll,uuu,8) + +#define GET_BIT(lll,uuu) \ + GET_BITS(lll,uuu,1) + +/*---------------------------------------------------*/ +#define GET_MTF_VAL(label1,label2,lval) \ +{ \ + if (groupPos == 0) { \ + groupNo++; \ + if (groupNo >= nSelectors) \ + RETURN(BZ_DATA_ERROR); \ + groupPos = BZ_G_SIZE; \ + gSel = s->selector[groupNo]; \ + gMinlen = s->minLens[gSel]; \ + gLimit = &(s->limit[gSel][0]); \ + gPerm = &(s->perm[gSel][0]); \ + gBase = &(s->base[gSel][0]); \ + } \ + groupPos--; \ + zn = gMinlen; \ + GET_BITS(label1, zvec, zn); \ + while (1) { \ + if (zn > 20 /* the longest code */) \ + RETURN(BZ_DATA_ERROR); \ + if (zvec <= gLimit[zn]) break; \ + zn++; \ + GET_BIT(label2, zj); \ + zvec = (zvec << 1) | zj; \ + }; \ + if (zvec - gBase[zn] < 0 \ + || zvec - gBase[zn] >= BZ_MAX_ALPHA_SIZE) \ + RETURN(BZ_DATA_ERROR); \ + lval = gPerm[zvec - gBase[zn]]; \ +} + + +/*---------------------------------------------------*/ +Int32 BZ2_decompress ( DState* s ) +{ + UChar uc; + Int32 retVal; + Int32 minLen, maxLen; + bz_stream* strm = s->strm; + + /* stuff that needs to be saved/restored */ + Int32 i; + Int32 j; + Int32 t; + Int32 alphaSize; + Int32 nGroups; + Int32 nSelectors; + Int32 EOB; + Int32 groupNo; + Int32 groupPos; + Int32 nextSym; + Int32 nblockMAX; + Int32 nblock; + Int32 es; + Int32 N; + Int32 curr; + Int32 zt; + Int32 zn; + Int32 zvec; + Int32 zj; + Int32 gSel; + Int32 gMinlen; + Int32* gLimit; + Int32* gBase; + Int32* gPerm; + + if (s->state == BZ_X_MAGIC_1) { + /*initialise the save area*/ + s->save_i = 0; + s->save_j = 0; + s->save_t = 0; + s->save_alphaSize = 0; + s->save_nGroups = 0; + s->save_nSelectors = 0; + s->save_EOB = 0; + s->save_groupNo = 0; + s->save_groupPos = 0; + s->save_nextSym = 0; + s->save_nblockMAX = 0; + s->save_nblock = 0; + s->save_es = 0; + s->save_N = 0; + s->save_curr = 0; + s->save_zt = 0; + s->save_zn = 0; + s->save_zvec = 0; + s->save_zj = 0; + s->save_gSel = 0; + s->save_gMinlen = 0; + s->save_gLimit = NULL; + s->save_gBase = NULL; + s->save_gPerm = NULL; + } + + /*restore from the save area*/ + i = s->save_i; + j = s->save_j; + t = s->save_t; + alphaSize = s->save_alphaSize; + nGroups = s->save_nGroups; + nSelectors = s->save_nSelectors; + EOB = s->save_EOB; + groupNo = s->save_groupNo; + groupPos = s->save_groupPos; + nextSym = s->save_nextSym; + nblockMAX = s->save_nblockMAX; + nblock = s->save_nblock; + es = s->save_es; + N = s->save_N; + curr = s->save_curr; + zt = s->save_zt; + zn = s->save_zn; + zvec = s->save_zvec; + zj = s->save_zj; + gSel = s->save_gSel; + gMinlen = s->save_gMinlen; + gLimit = s->save_gLimit; + gBase = s->save_gBase; + gPerm = s->save_gPerm; + + retVal = BZ_OK; + + switch (s->state) { + + GET_UCHAR(BZ_X_MAGIC_1, uc); + if (uc != BZ_HDR_B) RETURN(BZ_DATA_ERROR_MAGIC); + + GET_UCHAR(BZ_X_MAGIC_2, uc); + if (uc != BZ_HDR_Z) RETURN(BZ_DATA_ERROR_MAGIC); + + GET_UCHAR(BZ_X_MAGIC_3, uc) + if (uc != BZ_HDR_h) RETURN(BZ_DATA_ERROR_MAGIC); + + GET_BITS(BZ_X_MAGIC_4, s->blockSize100k, 8) + if (s->blockSize100k < (BZ_HDR_0 + 1) || + s->blockSize100k > (BZ_HDR_0 + 9)) RETURN(BZ_DATA_ERROR_MAGIC); + s->blockSize100k -= BZ_HDR_0; + + if (s->smallDecompress) { + s->ll16 = BZALLOC( s->blockSize100k * 100000 * sizeof(UInt16) ); + s->ll4 = BZALLOC( + ((1 + s->blockSize100k * 100000) >> 1) * sizeof(UChar) + ); + if (s->ll16 == NULL || s->ll4 == NULL) RETURN(BZ_MEM_ERROR); + } else { + s->tt = BZALLOC( s->blockSize100k * 100000 * sizeof(Int32) ); + if (s->tt == NULL) RETURN(BZ_MEM_ERROR); + } + + GET_UCHAR(BZ_X_BLKHDR_1, uc); + + if (uc == 0x17) goto endhdr_2; + if (uc != 0x31) RETURN(BZ_DATA_ERROR); + GET_UCHAR(BZ_X_BLKHDR_2, uc); + if (uc != 0x41) RETURN(BZ_DATA_ERROR); + GET_UCHAR(BZ_X_BLKHDR_3, uc); + if (uc != 0x59) RETURN(BZ_DATA_ERROR); + GET_UCHAR(BZ_X_BLKHDR_4, uc); + if (uc != 0x26) RETURN(BZ_DATA_ERROR); + GET_UCHAR(BZ_X_BLKHDR_5, uc); + if (uc != 0x53) RETURN(BZ_DATA_ERROR); + GET_UCHAR(BZ_X_BLKHDR_6, uc); + if (uc != 0x59) RETURN(BZ_DATA_ERROR); + + s->currBlockNo++; + if (s->verbosity >= 2) + VPrintf1 ( "\n [%d: huff+mtf ", s->currBlockNo ); + + s->storedBlockCRC = 0; + GET_UCHAR(BZ_X_BCRC_1, uc); + s->storedBlockCRC = (s->storedBlockCRC << 8) | ((UInt32)uc); + GET_UCHAR(BZ_X_BCRC_2, uc); + s->storedBlockCRC = (s->storedBlockCRC << 8) | ((UInt32)uc); + GET_UCHAR(BZ_X_BCRC_3, uc); + s->storedBlockCRC = (s->storedBlockCRC << 8) | ((UInt32)uc); + GET_UCHAR(BZ_X_BCRC_4, uc); + s->storedBlockCRC = (s->storedBlockCRC << 8) | ((UInt32)uc); + + GET_BITS(BZ_X_RANDBIT, s->blockRandomised, 1); + + s->origPtr = 0; + GET_UCHAR(BZ_X_ORIGPTR_1, uc); + s->origPtr = (s->origPtr << 8) | ((Int32)uc); + GET_UCHAR(BZ_X_ORIGPTR_2, uc); + s->origPtr = (s->origPtr << 8) | ((Int32)uc); + GET_UCHAR(BZ_X_ORIGPTR_3, uc); + s->origPtr = (s->origPtr << 8) | ((Int32)uc); + + if (s->origPtr < 0) + RETURN(BZ_DATA_ERROR); + if (s->origPtr > 10 + 100000*s->blockSize100k) + RETURN(BZ_DATA_ERROR); + + /*--- Receive the mapping table ---*/ + for (i = 0; i < 16; i++) { + GET_BIT(BZ_X_MAPPING_1, uc); + if (uc == 1) + s->inUse16[i] = True; else + s->inUse16[i] = False; + } + + for (i = 0; i < 256; i++) s->inUse[i] = False; + + for (i = 0; i < 16; i++) + if (s->inUse16[i]) + for (j = 0; j < 16; j++) { + GET_BIT(BZ_X_MAPPING_2, uc); + if (uc == 1) s->inUse[i * 16 + j] = True; + } + makeMaps_d ( s ); + if (s->nInUse == 0) RETURN(BZ_DATA_ERROR); + alphaSize = s->nInUse+2; + + /*--- Now the selectors ---*/ + GET_BITS(BZ_X_SELECTOR_1, nGroups, 3); + if (nGroups < 2 || nGroups > 6) RETURN(BZ_DATA_ERROR); + GET_BITS(BZ_X_SELECTOR_2, nSelectors, 15); + if (nSelectors < 1) RETURN(BZ_DATA_ERROR); + for (i = 0; i < nSelectors; i++) { + j = 0; + while (True) { + GET_BIT(BZ_X_SELECTOR_3, uc); + if (uc == 0) break; + j++; + if (j >= nGroups) RETURN(BZ_DATA_ERROR); + } + s->selectorMtf[i] = j; + } + + /*--- Undo the MTF values for the selectors. ---*/ + { + UChar pos[BZ_N_GROUPS], tmp, v; + for (v = 0; v < nGroups; v++) pos[v] = v; + + for (i = 0; i < nSelectors; i++) { + v = s->selectorMtf[i]; + tmp = pos[v]; + while (v > 0) { pos[v] = pos[v-1]; v--; } + pos[0] = tmp; + s->selector[i] = tmp; + } + } + + /*--- Now the coding tables ---*/ + for (t = 0; t < nGroups; t++) { + GET_BITS(BZ_X_CODING_1, curr, 5); + for (i = 0; i < alphaSize; i++) { + while (True) { + if (curr < 1 || curr > 20) RETURN(BZ_DATA_ERROR); + GET_BIT(BZ_X_CODING_2, uc); + if (uc == 0) break; + GET_BIT(BZ_X_CODING_3, uc); + if (uc == 0) curr++; else curr--; + } + s->len[t][i] = curr; + } + } + + /*--- Create the Huffman decoding tables ---*/ + for (t = 0; t < nGroups; t++) { + minLen = 32; + maxLen = 0; + for (i = 0; i < alphaSize; i++) { + if (s->len[t][i] > maxLen) maxLen = s->len[t][i]; + if (s->len[t][i] < minLen) minLen = s->len[t][i]; + } + BZ2_hbCreateDecodeTables ( + &(s->limit[t][0]), + &(s->base[t][0]), + &(s->perm[t][0]), + &(s->len[t][0]), + minLen, maxLen, alphaSize + ); + s->minLens[t] = minLen; + } + + /*--- Now the MTF values ---*/ + + EOB = s->nInUse+1; + nblockMAX = 100000 * s->blockSize100k; + groupNo = -1; + groupPos = 0; + + for (i = 0; i <= 255; i++) s->unzftab[i] = 0; + + /*-- MTF init --*/ + { + Int32 ii, jj, kk; + kk = MTFA_SIZE-1; + for (ii = 256 / MTFL_SIZE - 1; ii >= 0; ii--) { + for (jj = MTFL_SIZE-1; jj >= 0; jj--) { + s->mtfa[kk] = (UChar)(ii * MTFL_SIZE + jj); + kk--; + } + s->mtfbase[ii] = kk + 1; + } + } + /*-- end MTF init --*/ + + nblock = 0; + GET_MTF_VAL(BZ_X_MTF_1, BZ_X_MTF_2, nextSym); + + while (True) { + + if (nextSym == EOB) break; + + if (nextSym == BZ_RUNA || nextSym == BZ_RUNB) { + + es = -1; + N = 1; + do { + if (nextSym == BZ_RUNA) es = es + (0+1) * N; else + if (nextSym == BZ_RUNB) es = es + (1+1) * N; + N = N * 2; + GET_MTF_VAL(BZ_X_MTF_3, BZ_X_MTF_4, nextSym); + } + while (nextSym == BZ_RUNA || nextSym == BZ_RUNB); + + es++; + uc = s->seqToUnseq[ s->mtfa[s->mtfbase[0]] ]; + s->unzftab[uc] += es; + + if (s->smallDecompress) + while (es > 0) { + if (nblock >= nblockMAX) RETURN(BZ_DATA_ERROR); + s->ll16[nblock] = (UInt16)uc; + nblock++; + es--; + } + else + while (es > 0) { + if (nblock >= nblockMAX) RETURN(BZ_DATA_ERROR); + s->tt[nblock] = (UInt32)uc; + nblock++; + es--; + }; + + continue; + + } else { + + if (nblock >= nblockMAX) RETURN(BZ_DATA_ERROR); + + /*-- uc = MTF ( nextSym-1 ) --*/ + { + Int32 ii, jj, kk, pp, lno, off; + UInt32 nn; + nn = (UInt32)(nextSym - 1); + + if (nn < MTFL_SIZE) { + /* avoid general-case expense */ + pp = s->mtfbase[0]; + uc = s->mtfa[pp+nn]; + while (nn > 3) { + Int32 z = pp+nn; + s->mtfa[(z) ] = s->mtfa[(z)-1]; + s->mtfa[(z)-1] = s->mtfa[(z)-2]; + s->mtfa[(z)-2] = s->mtfa[(z)-3]; + s->mtfa[(z)-3] = s->mtfa[(z)-4]; + nn -= 4; + } + while (nn > 0) { + s->mtfa[(pp+nn)] = s->mtfa[(pp+nn)-1]; nn--; + }; + s->mtfa[pp] = uc; + } else { + /* general case */ + lno = nn / MTFL_SIZE; + off = nn % MTFL_SIZE; + pp = s->mtfbase[lno] + off; + uc = s->mtfa[pp]; + while (pp > s->mtfbase[lno]) { + s->mtfa[pp] = s->mtfa[pp-1]; pp--; + }; + s->mtfbase[lno]++; + while (lno > 0) { + s->mtfbase[lno]--; + s->mtfa[s->mtfbase[lno]] + = s->mtfa[s->mtfbase[lno-1] + MTFL_SIZE - 1]; + lno--; + } + s->mtfbase[0]--; + s->mtfa[s->mtfbase[0]] = uc; + if (s->mtfbase[0] == 0) { + kk = MTFA_SIZE-1; + for (ii = 256 / MTFL_SIZE-1; ii >= 0; ii--) { + for (jj = MTFL_SIZE-1; jj >= 0; jj--) { + s->mtfa[kk] = s->mtfa[s->mtfbase[ii] + jj]; + kk--; + } + s->mtfbase[ii] = kk + 1; + } + } + } + } + /*-- end uc = MTF ( nextSym-1 ) --*/ + + s->unzftab[s->seqToUnseq[uc]]++; + if (s->smallDecompress) + s->ll16[nblock] = (UInt16)(s->seqToUnseq[uc]); else + s->tt[nblock] = (UInt32)(s->seqToUnseq[uc]); + nblock++; + + GET_MTF_VAL(BZ_X_MTF_5, BZ_X_MTF_6, nextSym); + continue; + } + } + + /* Now we know what nblock is, we can do a better sanity + check on s->origPtr. + */ + if (s->origPtr < 0 || s->origPtr >= nblock) + RETURN(BZ_DATA_ERROR); + + /*-- Set up cftab to facilitate generation of T^(-1) --*/ + s->cftab[0] = 0; + for (i = 1; i <= 256; i++) s->cftab[i] = s->unzftab[i-1]; + for (i = 1; i <= 256; i++) s->cftab[i] += s->cftab[i-1]; + for (i = 0; i <= 256; i++) { + if (s->cftab[i] < 0 || s->cftab[i] > nblock) { + /* s->cftab[i] can legitimately be == nblock */ + RETURN(BZ_DATA_ERROR); + } + } + + s->state_out_len = 0; + s->state_out_ch = 0; + BZ_INITIALISE_CRC ( s->calculatedBlockCRC ); + s->state = BZ_X_OUTPUT; + if (s->verbosity >= 2) VPrintf0 ( "rt+rld" ); + + if (s->smallDecompress) { + + /*-- Make a copy of cftab, used in generation of T --*/ + for (i = 0; i <= 256; i++) s->cftabCopy[i] = s->cftab[i]; + + /*-- compute the T vector --*/ + for (i = 0; i < nblock; i++) { + uc = (UChar)(s->ll16[i]); + SET_LL(i, s->cftabCopy[uc]); + s->cftabCopy[uc]++; + } + + /*-- Compute T^(-1) by pointer reversal on T --*/ + i = s->origPtr; + j = GET_LL(i); + do { + Int32 tmp = GET_LL(j); + SET_LL(j, i); + i = j; + j = tmp; + } + while (i != s->origPtr); + + s->tPos = s->origPtr; + s->nblock_used = 0; + if (s->blockRandomised) { + BZ_RAND_INIT_MASK; + BZ_GET_SMALL(s->k0); s->nblock_used++; + BZ_RAND_UPD_MASK; s->k0 ^= BZ_RAND_MASK; + } else { + BZ_GET_SMALL(s->k0); s->nblock_used++; + } + + } else { + + /*-- compute the T^(-1) vector --*/ + for (i = 0; i < nblock; i++) { + uc = (UChar)(s->tt[i] & 0xff); + s->tt[s->cftab[uc]] |= (i << 8); + s->cftab[uc]++; + } + + s->tPos = s->tt[s->origPtr] >> 8; + s->nblock_used = 0; + if (s->blockRandomised) { + BZ_RAND_INIT_MASK; + BZ_GET_FAST(s->k0); s->nblock_used++; + BZ_RAND_UPD_MASK; s->k0 ^= BZ_RAND_MASK; + } else { + BZ_GET_FAST(s->k0); s->nblock_used++; + } + + } + + RETURN(BZ_OK); + + + + endhdr_2: + + GET_UCHAR(BZ_X_ENDHDR_2, uc); + if (uc != 0x72) RETURN(BZ_DATA_ERROR); + GET_UCHAR(BZ_X_ENDHDR_3, uc); + if (uc != 0x45) RETURN(BZ_DATA_ERROR); + GET_UCHAR(BZ_X_ENDHDR_4, uc); + if (uc != 0x38) RETURN(BZ_DATA_ERROR); + GET_UCHAR(BZ_X_ENDHDR_5, uc); + if (uc != 0x50) RETURN(BZ_DATA_ERROR); + GET_UCHAR(BZ_X_ENDHDR_6, uc); + if (uc != 0x90) RETURN(BZ_DATA_ERROR); + + s->storedCombinedCRC = 0; + GET_UCHAR(BZ_X_CCRC_1, uc); + s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((UInt32)uc); + GET_UCHAR(BZ_X_CCRC_2, uc); + s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((UInt32)uc); + GET_UCHAR(BZ_X_CCRC_3, uc); + s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((UInt32)uc); + GET_UCHAR(BZ_X_CCRC_4, uc); + s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((UInt32)uc); + + s->state = BZ_X_IDLE; + RETURN(BZ_STREAM_END); + + default: AssertH ( False, 4001 ); + } + + AssertH ( False, 4002 ); + + save_state_and_return: + + s->save_i = i; + s->save_j = j; + s->save_t = t; + s->save_alphaSize = alphaSize; + s->save_nGroups = nGroups; + s->save_nSelectors = nSelectors; + s->save_EOB = EOB; + s->save_groupNo = groupNo; + s->save_groupPos = groupPos; + s->save_nextSym = nextSym; + s->save_nblockMAX = nblockMAX; + s->save_nblock = nblock; + s->save_es = es; + s->save_N = N; + s->save_curr = curr; + s->save_zt = zt; + s->save_zn = zn; + s->save_zvec = zvec; + s->save_zj = zj; + s->save_gSel = gSel; + s->save_gMinlen = gMinlen; + s->save_gLimit = gLimit; + s->save_gBase = gBase; + s->save_gPerm = gPerm; + + return retVal; +} + + +/*-------------------------------------------------------------*/ +/*--- end decompress.c ---*/ +/*-------------------------------------------------------------*/ diff --git a/src/misc/bzlib/huffman.c b/src/misc/bzlib/huffman.c new file mode 100644 index 00000000..87e79e38 --- /dev/null +++ b/src/misc/bzlib/huffman.c @@ -0,0 +1,205 @@ + +/*-------------------------------------------------------------*/ +/*--- Huffman coding low-level stuff ---*/ +/*--- huffman.c ---*/ +/*-------------------------------------------------------------*/ + +/* ------------------------------------------------------------------ + This file is part of bzip2/libbzip2, a program and library for + lossless, block-sorting data compression. + + bzip2/libbzip2 version 1.0.5 of 10 December 2007 + Copyright (C) 1996-2007 Julian Seward <jseward@bzip.org> + + Please read the WARNING, DISCLAIMER and PATENTS sections in the + README file. + + This program is released under the terms of the license contained + in the file LICENSE. + ------------------------------------------------------------------ */ + + +#include "bzlib_private.h" + +/*---------------------------------------------------*/ +#define WEIGHTOF(zz0) ((zz0) & 0xffffff00) +#define DEPTHOF(zz1) ((zz1) & 0x000000ff) +#define MYMAX(zz2,zz3) ((zz2) > (zz3) ? (zz2) : (zz3)) + +#define ADDWEIGHTS(zw1,zw2) \ + (WEIGHTOF(zw1)+WEIGHTOF(zw2)) | \ + (1 + MYMAX(DEPTHOF(zw1),DEPTHOF(zw2))) + +#define UPHEAP(z) \ +{ \ + Int32 zz, tmp; \ + zz = z; tmp = heap[zz]; \ + while (weight[tmp] < weight[heap[zz >> 1]]) { \ + heap[zz] = heap[zz >> 1]; \ + zz >>= 1; \ + } \ + heap[zz] = tmp; \ +} + +#define DOWNHEAP(z) \ +{ \ + Int32 zz, yy, tmp; \ + zz = z; tmp = heap[zz]; \ + while (True) { \ + yy = zz << 1; \ + if (yy > nHeap) break; \ + if (yy < nHeap && \ + weight[heap[yy+1]] < weight[heap[yy]]) \ + yy++; \ + if (weight[tmp] < weight[heap[yy]]) break; \ + heap[zz] = heap[yy]; \ + zz = yy; \ + } \ + heap[zz] = tmp; \ +} + + +/*---------------------------------------------------*/ +void BZ2_hbMakeCodeLengths ( UChar *len, + Int32 *freq, + Int32 alphaSize, + Int32 maxLen ) +{ + /*-- + Nodes and heap entries run from 1. Entry 0 + for both the heap and nodes is a sentinel. + --*/ + Int32 nNodes, nHeap, n1, n2, i, j, k; + Bool tooLong; + + Int32 heap [ BZ_MAX_ALPHA_SIZE + 2 ]; + Int32 weight [ BZ_MAX_ALPHA_SIZE * 2 ]; + Int32 parent [ BZ_MAX_ALPHA_SIZE * 2 ]; + + for (i = 0; i < alphaSize; i++) + weight[i+1] = (freq[i] == 0 ? 1 : freq[i]) << 8; + + while (True) { + + nNodes = alphaSize; + nHeap = 0; + + heap[0] = 0; + weight[0] = 0; + parent[0] = -2; + + for (i = 1; i <= alphaSize; i++) { + parent[i] = -1; + nHeap++; + heap[nHeap] = i; + UPHEAP(nHeap); + } + + AssertH( nHeap < (BZ_MAX_ALPHA_SIZE+2), 2001 ); + + while (nHeap > 1) { + n1 = heap[1]; heap[1] = heap[nHeap]; nHeap--; DOWNHEAP(1); + n2 = heap[1]; heap[1] = heap[nHeap]; nHeap--; DOWNHEAP(1); + nNodes++; + parent[n1] = parent[n2] = nNodes; + weight[nNodes] = ADDWEIGHTS(weight[n1], weight[n2]); + parent[nNodes] = -1; + nHeap++; + heap[nHeap] = nNodes; + UPHEAP(nHeap); + } + + AssertH( nNodes < (BZ_MAX_ALPHA_SIZE * 2), 2002 ); + + tooLong = False; + for (i = 1; i <= alphaSize; i++) { + j = 0; + k = i; + while (parent[k] >= 0) { k = parent[k]; j++; } + len[i-1] = j; + if (j > maxLen) tooLong = True; + } + + if (! tooLong) break; + + /* 17 Oct 04: keep-going condition for the following loop used + to be 'i < alphaSize', which missed the last element, + theoretically leading to the possibility of the compressor + looping. However, this count-scaling step is only needed if + one of the generated Huffman code words is longer than + maxLen, which up to and including version 1.0.2 was 20 bits, + which is extremely unlikely. In version 1.0.3 maxLen was + changed to 17 bits, which has minimal effect on compression + ratio, but does mean this scaling step is used from time to + time, enough to verify that it works. + + This means that bzip2-1.0.3 and later will only produce + Huffman codes with a maximum length of 17 bits. However, in + order to preserve backwards compatibility with bitstreams + produced by versions pre-1.0.3, the decompressor must still + handle lengths of up to 20. */ + + for (i = 1; i <= alphaSize; i++) { + j = weight[i] >> 8; + j = 1 + (j / 2); + weight[i] = j << 8; + } + } +} + + +/*---------------------------------------------------*/ +void BZ2_hbAssignCodes ( Int32 *code, + UChar *length, + Int32 minLen, + Int32 maxLen, + Int32 alphaSize ) +{ + Int32 n, vec, i; + + vec = 0; + for (n = minLen; n <= maxLen; n++) { + for (i = 0; i < alphaSize; i++) + if (length[i] == n) { code[i] = vec; vec++; }; + vec <<= 1; + } +} + + +/*---------------------------------------------------*/ +void BZ2_hbCreateDecodeTables ( Int32 *limit, + Int32 *base, + Int32 *perm, + UChar *length, + Int32 minLen, + Int32 maxLen, + Int32 alphaSize ) +{ + Int32 pp, i, j, vec; + + pp = 0; + for (i = minLen; i <= maxLen; i++) + for (j = 0; j < alphaSize; j++) + if (length[j] == i) { perm[pp] = j; pp++; }; + + for (i = 0; i < BZ_MAX_CODE_LEN; i++) base[i] = 0; + for (i = 0; i < alphaSize; i++) base[length[i]+1]++; + + for (i = 1; i < BZ_MAX_CODE_LEN; i++) base[i] += base[i-1]; + + for (i = 0; i < BZ_MAX_CODE_LEN; i++) limit[i] = 0; + vec = 0; + + for (i = minLen; i <= maxLen; i++) { + vec += (base[i+1] - base[i]); + limit[i] = vec-1; + vec <<= 1; + } + for (i = minLen + 1; i <= maxLen; i++) + base[i] = ((limit[i-1] + 1) << 1) - base[i]; +} + + +/*-------------------------------------------------------------*/ +/*--- end huffman.c ---*/ +/*-------------------------------------------------------------*/ diff --git a/src/misc/bzlib/link.txt b/src/misc/bzlib/link.txt new file mode 100644 index 00000000..cdfca2df --- /dev/null +++ b/src/misc/bzlib/link.txt @@ -0,0 +1,2 @@ +http://www.bzip.org +http://gnuwin32.sourceforge.net/packages/bzip2.htm diff --git a/src/misc/bzlib/manual.html b/src/misc/bzlib/manual.html new file mode 100644 index 00000000..68259b27 --- /dev/null +++ b/src/misc/bzlib/manual.html @@ -0,0 +1,2540 @@ +<html> +<head> +<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"> +<title>bzip2 and libbzip2, version 1.0.5</title> +<meta name="generator" content="DocBook XSL Stylesheets V1.69.1"> +<style type="text/css" media="screen">/* Colours: +#74240f dark brown h1, h2, h3, h4 +#336699 medium blue links +#339999 turquoise link hover colour +#202020 almost black general text +#761596 purple md5sum text +#626262 dark gray pre border +#eeeeee very light gray pre background +#f2f2f9 very light blue nav table background +#3366cc medium blue nav table border +*/ + +a, a:link, a:visited, a:active { color: #336699; } +a:hover { color: #339999; } + +body { font: 80%/126% sans-serif; } +h1, h2, h3, h4 { color: #74240f; } + +dt { color: #336699; font-weight: bold } +dd { + margin-left: 1.5em; + padding-bottom: 0.8em; +} + +/* -- ruler -- */ +div.hr_blue { + height: 3px; + background:#ffffff url("/images/hr_blue.png") repeat-x; } +div.hr_blue hr { display:none; } + +/* release styles */ +#release p { margin-top: 0.4em; } +#release .md5sum { color: #761596; } + + +/* ------ styles for docs|manuals|howto ------ */ +/* -- lists -- */ +ul { + margin: 0px 4px 16px 16px; + padding: 0px; + list-style: url("/images/li-blue.png"); +} +ul li { + margin-bottom: 10px; +} +ul ul { + list-style-type: none; + list-style-image: none; + margin-left: 0px; +} + +/* header / footer nav tables */ +table.nav { + border: solid 1px #3366cc; + background: #f2f2f9; + background-color: #f2f2f9; + margin-bottom: 0.5em; +} +/* don't have underlined links in chunked nav menus */ +table.nav a { text-decoration: none; } +table.nav a:hover { text-decoration: underline; } +table.nav td { font-size: 85%; } + +code, tt, pre { font-size: 120%; } +code, tt { color: #761596; } + +div.literallayout, pre.programlisting, pre.screen { + color: #000000; + padding: 0.5em; + background: #eeeeee; + border: 1px solid #626262; + background-color: #eeeeee; + margin: 4px 0px 4px 0px; +} +</style> +</head> +<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="book" lang="en"> +<div class="titlepage"> +<div> +<div><h1 class="title"> +<a name="userman"></a>bzip2 and libbzip2, version 1.0.5</h1></div> +<div><h2 class="subtitle">A program and library for data compression</h2></div> +<div><div class="authorgroup"><div class="author"> +<h3 class="author"> +<span class="firstname">Julian</span> <span class="surname">Seward</span> +</h3> +<div class="affiliation"><span class="orgname">http://www.bzip.org<br></span></div> +</div></div></div> +<div><p class="releaseinfo">Version 1.0.5 of 10 December 2007</p></div> +<div><p class="copyright">Copyright © 1996-2007 Julian Seward</p></div> +<div><div class="legalnotice"> +<a name="id2499833"></a><p>This program, <code class="computeroutput">bzip2</code>, the + associated library <code class="computeroutput">libbzip2</code>, and + all documentation, are copyright © 1996-2007 Julian Seward. + All rights reserved.</p> +<p>Redistribution and use in source and binary forms, with + or without modification, are permitted provided that the + following conditions are met:</p> +<div class="itemizedlist"><ul type="bullet"> +<li style="list-style-type: disc"><p>Redistributions of source code must retain the + above copyright notice, this list of conditions and the + following disclaimer.</p></li> +<li style="list-style-type: disc"><p>The origin of this software must not be + misrepresented; you must not claim that you wrote the original + software. If you use this software in a product, an + acknowledgment in the product documentation would be + appreciated but is not required.</p></li> +<li style="list-style-type: disc"><p>Altered source versions must be plainly marked + as such, and must not be misrepresented as being the original + software.</p></li> +<li style="list-style-type: disc"><p>The name of the author may not be used to + endorse or promote products derived from this software without + specific prior written permission.</p></li> +</ul></div> +<p>THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY + EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + THE POSSIBILITY OF SUCH DAMAGE.</p> +<p>PATENTS: To the best of my knowledge, + <code class="computeroutput">bzip2</code> and + <code class="computeroutput">libbzip2</code> do not use any patented + algorithms. However, I do not have the resources to carry + out a patent search. Therefore I cannot give any guarantee of + the above statement. + </p> +</div></div> +</div> +<hr> +</div> +<div class="toc"> +<p><b>Table of Contents</b></p> +<dl> +<dt><span class="chapter"><a href="#intro">1. Introduction</a></span></dt> +<dt><span class="chapter"><a href="#using">2. How to use bzip2</a></span></dt> +<dd><dl> +<dt><span class="sect1"><a href="#name">2.1. NAME</a></span></dt> +<dt><span class="sect1"><a href="#synopsis">2.2. SYNOPSIS</a></span></dt> +<dt><span class="sect1"><a href="#description">2.3. DESCRIPTION</a></span></dt> +<dt><span class="sect1"><a href="#options">2.4. OPTIONS</a></span></dt> +<dt><span class="sect1"><a href="#memory-management">2.5. MEMORY MANAGEMENT</a></span></dt> +<dt><span class="sect1"><a href="#recovering">2.6. RECOVERING DATA FROM DAMAGED FILES</a></span></dt> +<dt><span class="sect1"><a href="#performance">2.7. PERFORMANCE NOTES</a></span></dt> +<dt><span class="sect1"><a href="#caveats">2.8. CAVEATS</a></span></dt> +<dt><span class="sect1"><a href="#author">2.9. AUTHOR</a></span></dt> +</dl></dd> +<dt><span class="chapter"><a href="#libprog">3. +Programming with <code class="computeroutput">libbzip2</code> +</a></span></dt> +<dd><dl> +<dt><span class="sect1"><a href="#top-level">3.1. Top-level structure</a></span></dt> +<dd><dl> +<dt><span class="sect2"><a href="#ll-summary">3.1.1. Low-level summary</a></span></dt> +<dt><span class="sect2"><a href="#hl-summary">3.1.2. High-level summary</a></span></dt> +<dt><span class="sect2"><a href="#util-fns-summary">3.1.3. Utility functions summary</a></span></dt> +</dl></dd> +<dt><span class="sect1"><a href="#err-handling">3.2. Error handling</a></span></dt> +<dt><span class="sect1"><a href="#low-level">3.3. Low-level interface</a></span></dt> +<dd><dl> +<dt><span class="sect2"><a href="#bzcompress-init">3.3.1. <code class="computeroutput">BZ2_bzCompressInit</code></a></span></dt> +<dt><span class="sect2"><a href="#bzCompress">3.3.2. <code class="computeroutput">BZ2_bzCompress</code></a></span></dt> +<dt><span class="sect2"><a href="#bzCompress-end">3.3.3. <code class="computeroutput">BZ2_bzCompressEnd</code></a></span></dt> +<dt><span class="sect2"><a href="#bzDecompress-init">3.3.4. <code class="computeroutput">BZ2_bzDecompressInit</code></a></span></dt> +<dt><span class="sect2"><a href="#bzDecompress">3.3.5. <code class="computeroutput">BZ2_bzDecompress</code></a></span></dt> +<dt><span class="sect2"><a href="#bzDecompress-end">3.3.6. <code class="computeroutput">BZ2_bzDecompressEnd</code></a></span></dt> +</dl></dd> +<dt><span class="sect1"><a href="#hl-interface">3.4. High-level interface</a></span></dt> +<dd><dl> +<dt><span class="sect2"><a href="#bzreadopen">3.4.1. <code class="computeroutput">BZ2_bzReadOpen</code></a></span></dt> +<dt><span class="sect2"><a href="#bzread">3.4.2. <code class="computeroutput">BZ2_bzRead</code></a></span></dt> +<dt><span class="sect2"><a href="#bzreadgetunused">3.4.3. <code class="computeroutput">BZ2_bzReadGetUnused</code></a></span></dt> +<dt><span class="sect2"><a href="#bzreadclose">3.4.4. <code class="computeroutput">BZ2_bzReadClose</code></a></span></dt> +<dt><span class="sect2"><a href="#bzwriteopen">3.4.5. <code class="computeroutput">BZ2_bzWriteOpen</code></a></span></dt> +<dt><span class="sect2"><a href="#bzwrite">3.4.6. <code class="computeroutput">BZ2_bzWrite</code></a></span></dt> +<dt><span class="sect2"><a href="#bzwriteclose">3.4.7. <code class="computeroutput">BZ2_bzWriteClose</code></a></span></dt> +<dt><span class="sect2"><a href="#embed">3.4.8. Handling embedded compressed data streams</a></span></dt> +<dt><span class="sect2"><a href="#std-rdwr">3.4.9. Standard file-reading/writing code</a></span></dt> +</dl></dd> +<dt><span class="sect1"><a href="#util-fns">3.5. Utility functions</a></span></dt> +<dd><dl> +<dt><span class="sect2"><a href="#bzbufftobuffcompress">3.5.1. <code class="computeroutput">BZ2_bzBuffToBuffCompress</code></a></span></dt> +<dt><span class="sect2"><a href="#bzbufftobuffdecompress">3.5.2. <code class="computeroutput">BZ2_bzBuffToBuffDecompress</code></a></span></dt> +</dl></dd> +<dt><span class="sect1"><a href="#zlib-compat">3.6. <code class="computeroutput">zlib</code> compatibility functions</a></span></dt> +<dt><span class="sect1"><a href="#stdio-free">3.7. Using the library in a <code class="computeroutput">stdio</code>-free environment</a></span></dt> +<dd><dl> +<dt><span class="sect2"><a href="#stdio-bye">3.7.1. Getting rid of <code class="computeroutput">stdio</code></a></span></dt> +<dt><span class="sect2"><a href="#critical-error">3.7.2. Critical error handling</a></span></dt> +</dl></dd> +<dt><span class="sect1"><a href="#win-dll">3.8. Making a Windows DLL</a></span></dt> +</dl></dd> +<dt><span class="chapter"><a href="#misc">4. Miscellanea</a></span></dt> +<dd><dl> +<dt><span class="sect1"><a href="#limits">4.1. Limitations of the compressed file format</a></span></dt> +<dt><span class="sect1"><a href="#port-issues">4.2. Portability issues</a></span></dt> +<dt><span class="sect1"><a href="#bugs">4.3. Reporting bugs</a></span></dt> +<dt><span class="sect1"><a href="#package">4.4. Did you get the right package?</a></span></dt> +<dt><span class="sect1"><a href="#reading">4.5. Further Reading</a></span></dt> +</dl></dd> +</dl> +</div> +<div class="chapter" lang="en"> +<div class="titlepage"><div><div><h2 class="title"> +<a name="intro"></a>1. Introduction</h2></div></div></div> +<p><code class="computeroutput">bzip2</code> compresses files +using the Burrows-Wheeler block-sorting text compression +algorithm, and Huffman coding. Compression is generally +considerably better than that achieved by more conventional +LZ77/LZ78-based compressors, and approaches the performance of +the PPM family of statistical compressors.</p> +<p><code class="computeroutput">bzip2</code> is built on top of +<code class="computeroutput">libbzip2</code>, a flexible library for +handling compressed data in the +<code class="computeroutput">bzip2</code> format. This manual +describes both how to use the program and how to work with the +library interface. Most of the manual is devoted to this +library, not the program, which is good news if your interest is +only in the program.</p> +<div class="itemizedlist"><ul type="bullet"> +<li style="list-style-type: disc"><p><a href="#using">How to use bzip2</a> describes how to use + <code class="computeroutput">bzip2</code>; this is the only part + you need to read if you just want to know how to operate the + program.</p></li> +<li style="list-style-type: disc"><p><a href="#libprog">Programming with libbzip2</a> describes the + programming interfaces in detail, and</p></li> +<li style="list-style-type: disc"><p><a href="#misc">Miscellanea</a> records some + miscellaneous notes which I thought ought to be recorded + somewhere.</p></li> +</ul></div> +</div> +<div class="chapter" lang="en"> +<div class="titlepage"><div><div><h2 class="title"> +<a name="using"></a>2. How to use bzip2</h2></div></div></div> +<div class="toc"> +<p><b>Table of Contents</b></p> +<dl> +<dt><span class="sect1"><a href="#name">2.1. NAME</a></span></dt> +<dt><span class="sect1"><a href="#synopsis">2.2. SYNOPSIS</a></span></dt> +<dt><span class="sect1"><a href="#description">2.3. DESCRIPTION</a></span></dt> +<dt><span class="sect1"><a href="#options">2.4. OPTIONS</a></span></dt> +<dt><span class="sect1"><a href="#memory-management">2.5. MEMORY MANAGEMENT</a></span></dt> +<dt><span class="sect1"><a href="#recovering">2.6. RECOVERING DATA FROM DAMAGED FILES</a></span></dt> +<dt><span class="sect1"><a href="#performance">2.7. PERFORMANCE NOTES</a></span></dt> +<dt><span class="sect1"><a href="#caveats">2.8. CAVEATS</a></span></dt> +<dt><span class="sect1"><a href="#author">2.9. AUTHOR</a></span></dt> +</dl> +</div> +<p>This chapter contains a copy of the +<code class="computeroutput">bzip2</code> man page, and nothing +else.</p> +<div class="sect1" lang="en"> +<div class="titlepage"><div><div><h2 class="title" style="clear: both"> +<a name="name"></a>2.1. NAME</h2></div></div></div> +<div class="itemizedlist"><ul type="bullet"> +<li style="list-style-type: disc"><p><code class="computeroutput">bzip2</code>, + <code class="computeroutput">bunzip2</code> - a block-sorting file + compressor, v1.0.4</p></li> +<li style="list-style-type: disc"><p><code class="computeroutput">bzcat</code> - + decompresses files to stdout</p></li> +<li style="list-style-type: disc"><p><code class="computeroutput">bzip2recover</code> - + recovers data from damaged bzip2 files</p></li> +</ul></div> +</div> +<div class="sect1" lang="en"> +<div class="titlepage"><div><div><h2 class="title" style="clear: both"> +<a name="synopsis"></a>2.2. SYNOPSIS</h2></div></div></div> +<div class="itemizedlist"><ul type="bullet"> +<li style="list-style-type: disc"><p><code class="computeroutput">bzip2</code> [ + -cdfkqstvzVL123456789 ] [ filenames ... ]</p></li> +<li style="list-style-type: disc"><p><code class="computeroutput">bunzip2</code> [ + -fkvsVL ] [ filenames ... ]</p></li> +<li style="list-style-type: disc"><p><code class="computeroutput">bzcat</code> [ -s ] [ + filenames ... ]</p></li> +<li style="list-style-type: disc"><p><code class="computeroutput">bzip2recover</code> + filename</p></li> +</ul></div> +</div> +<div class="sect1" lang="en"> +<div class="titlepage"><div><div><h2 class="title" style="clear: both"> +<a name="description"></a>2.3. DESCRIPTION</h2></div></div></div> +<p><code class="computeroutput">bzip2</code> compresses files +using the Burrows-Wheeler block sorting text compression +algorithm, and Huffman coding. Compression is generally +considerably better than that achieved by more conventional +LZ77/LZ78-based compressors, and approaches the performance of +the PPM family of statistical compressors.</p> +<p>The command-line options are deliberately very similar to +those of GNU <code class="computeroutput">gzip</code>, but they are +not identical.</p> +<p><code class="computeroutput">bzip2</code> expects a list of +file names to accompany the command-line flags. Each file is +replaced by a compressed version of itself, with the name +<code class="computeroutput">original_name.bz2</code>. Each +compressed file has the same modification date, permissions, and, +when possible, ownership as the corresponding original, so that +these properties can be correctly restored at decompression time. +File name handling is naive in the sense that there is no +mechanism for preserving original file names, permissions, +ownerships or dates in filesystems which lack these concepts, or +have serious file name length restrictions, such as +MS-DOS.</p> +<p><code class="computeroutput">bzip2</code> and +<code class="computeroutput">bunzip2</code> will by default not +overwrite existing files. If you want this to happen, specify +the <code class="computeroutput">-f</code> flag.</p> +<p>If no file names are specified, +<code class="computeroutput">bzip2</code> compresses from standard +input to standard output. In this case, +<code class="computeroutput">bzip2</code> will decline to write +compressed output to a terminal, as this would be entirely +incomprehensible and therefore pointless.</p> +<p><code class="computeroutput">bunzip2</code> (or +<code class="computeroutput">bzip2 -d</code>) decompresses all +specified files. Files which were not created by +<code class="computeroutput">bzip2</code> will be detected and +ignored, and a warning issued. +<code class="computeroutput">bzip2</code> attempts to guess the +filename for the decompressed file from that of the compressed +file as follows:</p> +<div class="itemizedlist"><ul type="bullet"> +<li style="list-style-type: disc"><p><code class="computeroutput">filename.bz2 </code> + becomes + <code class="computeroutput">filename</code></p></li> +<li style="list-style-type: disc"><p><code class="computeroutput">filename.bz </code> + becomes + <code class="computeroutput">filename</code></p></li> +<li style="list-style-type: disc"><p><code class="computeroutput">filename.tbz2</code> + becomes + <code class="computeroutput">filename.tar</code></p></li> +<li style="list-style-type: disc"><p><code class="computeroutput">filename.tbz </code> + becomes + <code class="computeroutput">filename.tar</code></p></li> +<li style="list-style-type: disc"><p><code class="computeroutput">anyothername </code> + becomes + <code class="computeroutput">anyothername.out</code></p></li> +</ul></div> +<p>If the file does not end in one of the recognised endings, +<code class="computeroutput">.bz2</code>, +<code class="computeroutput">.bz</code>, +<code class="computeroutput">.tbz2</code> or +<code class="computeroutput">.tbz</code>, +<code class="computeroutput">bzip2</code> complains that it cannot +guess the name of the original file, and uses the original name +with <code class="computeroutput">.out</code> appended.</p> +<p>As with compression, supplying no filenames causes +decompression from standard input to standard output.</p> +<p><code class="computeroutput">bunzip2</code> will correctly +decompress a file which is the concatenation of two or more +compressed files. The result is the concatenation of the +corresponding uncompressed files. Integrity testing +(<code class="computeroutput">-t</code>) of concatenated compressed +files is also supported.</p> +<p>You can also compress or decompress files to the standard +output by giving the <code class="computeroutput">-c</code> flag. +Multiple files may be compressed and decompressed like this. The +resulting outputs are fed sequentially to stdout. Compression of +multiple files in this manner generates a stream containing +multiple compressed file representations. Such a stream can be +decompressed correctly only by +<code class="computeroutput">bzip2</code> version 0.9.0 or later. +Earlier versions of <code class="computeroutput">bzip2</code> will +stop after decompressing the first file in the stream.</p> +<p><code class="computeroutput">bzcat</code> (or +<code class="computeroutput">bzip2 -dc</code>) decompresses all +specified files to the standard output.</p> +<p><code class="computeroutput">bzip2</code> will read arguments +from the environment variables +<code class="computeroutput">BZIP2</code> and +<code class="computeroutput">BZIP</code>, in that order, and will +process them before any arguments read from the command line. +This gives a convenient way to supply default arguments.</p> +<p>Compression is always performed, even if the compressed +file is slightly larger than the original. Files of less than +about one hundred bytes tend to get larger, since the compression +mechanism has a constant overhead in the region of 50 bytes. +Random data (including the output of most file compressors) is +coded at about 8.05 bits per byte, giving an expansion of around +0.5%.</p> +<p>As a self-check for your protection, +<code class="computeroutput">bzip2</code> uses 32-bit CRCs to make +sure that the decompressed version of a file is identical to the +original. This guards against corruption of the compressed data, +and against undetected bugs in +<code class="computeroutput">bzip2</code> (hopefully very unlikely). +The chances of data corruption going undetected is microscopic, +about one chance in four billion for each file processed. Be +aware, though, that the check occurs upon decompression, so it +can only tell you that something is wrong. It can't help you +recover the original uncompressed data. You can use +<code class="computeroutput">bzip2recover</code> to try to recover +data from damaged files.</p> +<p>Return values: 0 for a normal exit, 1 for environmental +problems (file not found, invalid flags, I/O errors, etc.), 2 +to indicate a corrupt compressed file, 3 for an internal +consistency error (eg, bug) which caused +<code class="computeroutput">bzip2</code> to panic.</p> +</div> +<div class="sect1" lang="en"> +<div class="titlepage"><div><div><h2 class="title" style="clear: both"> +<a name="options"></a>2.4. OPTIONS</h2></div></div></div> +<div class="variablelist"><dl> +<dt><span class="term"><code class="computeroutput">-c --stdout</code></span></dt> +<dd><p>Compress or decompress to standard + output.</p></dd> +<dt><span class="term"><code class="computeroutput">-d --decompress</code></span></dt> +<dd><p>Force decompression. + <code class="computeroutput">bzip2</code>, + <code class="computeroutput">bunzip2</code> and + <code class="computeroutput">bzcat</code> are really the same + program, and the decision about what actions to take is done on + the basis of which name is used. This flag overrides that + mechanism, and forces bzip2 to decompress.</p></dd> +<dt><span class="term"><code class="computeroutput">-z --compress</code></span></dt> +<dd><p>The complement to + <code class="computeroutput">-d</code>: forces compression, + regardless of the invokation name.</p></dd> +<dt><span class="term"><code class="computeroutput">-t --test</code></span></dt> +<dd><p>Check integrity of the specified file(s), but + don't decompress them. This really performs a trial + decompression and throws away the result.</p></dd> +<dt><span class="term"><code class="computeroutput">-f --force</code></span></dt> +<dd> +<p>Force overwrite of output files. Normally, + <code class="computeroutput">bzip2</code> will not overwrite + existing output files. Also forces + <code class="computeroutput">bzip2</code> to break hard links to + files, which it otherwise wouldn't do.</p> +<p><code class="computeroutput">bzip2</code> normally declines + to decompress files which don't have the correct magic header + bytes. If forced (<code class="computeroutput">-f</code>), + however, it will pass such files through unmodified. This is + how GNU <code class="computeroutput">gzip</code> behaves.</p> +</dd> +<dt><span class="term"><code class="computeroutput">-k --keep</code></span></dt> +<dd><p>Keep (don't delete) input files during + compression or decompression.</p></dd> +<dt><span class="term"><code class="computeroutput">-s --small</code></span></dt> +<dd> +<p>Reduce memory usage, for compression, + decompression and testing. Files are decompressed and tested + using a modified algorithm which only requires 2.5 bytes per + block byte. This means any file can be decompressed in 2300k + of memory, albeit at about half the normal speed.</p> +<p>During compression, <code class="computeroutput">-s</code> + selects a block size of 200k, which limits memory use to around + the same figure, at the expense of your compression ratio. In + short, if your machine is low on memory (8 megabytes or less), + use <code class="computeroutput">-s</code> for everything. See + <a href="#memory-management">MEMORY MANAGEMENT</a> below.</p> +</dd> +<dt><span class="term"><code class="computeroutput">-q --quiet</code></span></dt> +<dd><p>Suppress non-essential warning messages. + Messages pertaining to I/O errors and other critical events + will not be suppressed.</p></dd> +<dt><span class="term"><code class="computeroutput">-v --verbose</code></span></dt> +<dd><p>Verbose mode -- show the compression ratio for + each file processed. Further + <code class="computeroutput">-v</code>'s increase the verbosity + level, spewing out lots of information which is primarily of + interest for diagnostic purposes.</p></dd> +<dt><span class="term"><code class="computeroutput">-L --license -V --version</code></span></dt> +<dd><p>Display the software version, license terms and + conditions.</p></dd> +<dt><span class="term"><code class="computeroutput">-1</code> (or + <code class="computeroutput">--fast</code>) to + <code class="computeroutput">-9</code> (or + <code class="computeroutput">-best</code>)</span></dt> +<dd><p>Set the block size to 100 k, 200 k ... 900 k + when compressing. Has no effect when decompressing. See <a href="#memory-management">MEMORY MANAGEMENT</a> below. The + <code class="computeroutput">--fast</code> and + <code class="computeroutput">--best</code> aliases are primarily + for GNU <code class="computeroutput">gzip</code> compatibility. + In particular, <code class="computeroutput">--fast</code> doesn't + make things significantly faster. And + <code class="computeroutput">--best</code> merely selects the + default behaviour.</p></dd> +<dt><span class="term"><code class="computeroutput">--</code></span></dt> +<dd><p>Treats all subsequent arguments as file names, + even if they start with a dash. This is so you can handle + files with names beginning with a dash, for example: + <code class="computeroutput">bzip2 -- + -myfilename</code>.</p></dd> +<dt> +<span class="term"><code class="computeroutput">--repetitive-fast</code>, </span><span class="term"><code class="computeroutput">--repetitive-best</code></span> +</dt> +<dd><p>These flags are redundant in versions 0.9.5 and + above. They provided some coarse control over the behaviour of + the sorting algorithm in earlier versions, which was sometimes + useful. 0.9.5 and above have an improved algorithm which + renders these flags irrelevant.</p></dd> +</dl></div> +</div> +<div class="sect1" lang="en"> +<div class="titlepage"><div><div><h2 class="title" style="clear: both"> +<a name="memory-management"></a>2.5. MEMORY MANAGEMENT</h2></div></div></div> +<p><code class="computeroutput">bzip2</code> compresses large +files in blocks. The block size affects both the compression +ratio achieved, and the amount of memory needed for compression +and decompression. The flags <code class="computeroutput">-1</code> +through <code class="computeroutput">-9</code> specify the block +size to be 100,000 bytes through 900,000 bytes (the default) +respectively. At decompression time, the block size used for +compression is read from the header of the compressed file, and +<code class="computeroutput">bunzip2</code> then allocates itself +just enough memory to decompress the file. Since block sizes are +stored in compressed files, it follows that the flags +<code class="computeroutput">-1</code> to +<code class="computeroutput">-9</code> are irrelevant to and so +ignored during decompression.</p> +<p>Compression and decompression requirements, in bytes, can be +estimated as:</p> +<pre class="programlisting">Compression: 400k + ( 8 x block size ) + +Decompression: 100k + ( 4 x block size ), or + 100k + ( 2.5 x block size )</pre> +<p>Larger block sizes give rapidly diminishing marginal +returns. Most of the compression comes from the first two or +three hundred k of block size, a fact worth bearing in mind when +using <code class="computeroutput">bzip2</code> on small machines. +It is also important to appreciate that the decompression memory +requirement is set at compression time by the choice of block +size.</p> +<p>For files compressed with the default 900k block size, +<code class="computeroutput">bunzip2</code> will require about 3700 +kbytes to decompress. To support decompression of any file on a +4 megabyte machine, <code class="computeroutput">bunzip2</code> has +an option to decompress using approximately half this amount of +memory, about 2300 kbytes. Decompression speed is also halved, +so you should use this option only where necessary. The relevant +flag is <code class="computeroutput">-s</code>.</p> +<p>In general, try and use the largest block size memory +constraints allow, since that maximises the compression achieved. +Compression and decompression speed are virtually unaffected by +block size.</p> +<p>Another significant point applies to files which fit in a +single block -- that means most files you'd encounter using a +large block size. The amount of real memory touched is +proportional to the size of the file, since the file is smaller +than a block. For example, compressing a file 20,000 bytes long +with the flag <code class="computeroutput">-9</code> will cause the +compressor to allocate around 7600k of memory, but only touch +400k + 20000 * 8 = 560 kbytes of it. Similarly, the decompressor +will allocate 3700k but only touch 100k + 20000 * 4 = 180 +kbytes.</p> +<p>Here is a table which summarises the maximum memory usage +for different block sizes. Also recorded is the total compressed +size for 14 files of the Calgary Text Compression Corpus +totalling 3,141,622 bytes. This column gives some feel for how +compression varies with block size. These figures tend to +understate the advantage of larger block sizes for larger files, +since the Corpus is dominated by smaller files.</p> +<pre class="programlisting"> Compress Decompress Decompress Corpus +Flag usage usage -s usage Size + + -1 1200k 500k 350k 914704 + -2 2000k 900k 600k 877703 + -3 2800k 1300k 850k 860338 + -4 3600k 1700k 1100k 846899 + -5 4400k 2100k 1350k 845160 + -6 5200k 2500k 1600k 838626 + -7 6100k 2900k 1850k 834096 + -8 6800k 3300k 2100k 828642 + -9 7600k 3700k 2350k 828642</pre> +</div> +<div class="sect1" lang="en"> +<div class="titlepage"><div><div><h2 class="title" style="clear: both"> +<a name="recovering"></a>2.6. RECOVERING DATA FROM DAMAGED FILES</h2></div></div></div> +<p><code class="computeroutput">bzip2</code> compresses files in +blocks, usually 900kbytes long. Each block is handled +independently. If a media or transmission error causes a +multi-block <code class="computeroutput">.bz2</code> file to become +damaged, it may be possible to recover data from the undamaged +blocks in the file.</p> +<p>The compressed representation of each block is delimited by +a 48-bit pattern, which makes it possible to find the block +boundaries with reasonable certainty. Each block also carries +its own 32-bit CRC, so damaged blocks can be distinguished from +undamaged ones.</p> +<p><code class="computeroutput">bzip2recover</code> is a simple +program whose purpose is to search for blocks in +<code class="computeroutput">.bz2</code> files, and write each block +out into its own <code class="computeroutput">.bz2</code> file. You +can then use <code class="computeroutput">bzip2 -t</code> to test +the integrity of the resulting files, and decompress those which +are undamaged.</p> +<p><code class="computeroutput">bzip2recover</code> takes a +single argument, the name of the damaged file, and writes a +number of files <code class="computeroutput">rec0001file.bz2</code>, +<code class="computeroutput">rec0002file.bz2</code>, etc, containing +the extracted blocks. The output filenames are designed so that +the use of wildcards in subsequent processing -- for example, +<code class="computeroutput">bzip2 -dc rec*file.bz2 > +recovered_data</code> -- lists the files in the correct +order.</p> +<p><code class="computeroutput">bzip2recover</code> should be of +most use dealing with large <code class="computeroutput">.bz2</code> +files, as these will contain many blocks. It is clearly futile +to use it on damaged single-block files, since a damaged block +cannot be recovered. If you wish to minimise any potential data +loss through media or transmission errors, you might consider +compressing with a smaller block size.</p> +</div> +<div class="sect1" lang="en"> +<div class="titlepage"><div><div><h2 class="title" style="clear: both"> +<a name="performance"></a>2.7. PERFORMANCE NOTES</h2></div></div></div> +<p>The sorting phase of compression gathers together similar +strings in the file. Because of this, files containing very long +runs of repeated symbols, like "aabaabaabaab ..." (repeated +several hundred times) may compress more slowly than normal. +Versions 0.9.5 and above fare much better than previous versions +in this respect. The ratio between worst-case and average-case +compression time is in the region of 10:1. For previous +versions, this figure was more like 100:1. You can use the +<code class="computeroutput">-vvvv</code> option to monitor progress +in great detail, if you want.</p> +<p>Decompression speed is unaffected by these +phenomena.</p> +<p><code class="computeroutput">bzip2</code> usually allocates +several megabytes of memory to operate in, and then charges all +over it in a fairly random fashion. This means that performance, +both for compressing and decompressing, is largely determined by +the speed at which your machine can service cache misses. +Because of this, small changes to the code to reduce the miss +rate have been observed to give disproportionately large +performance improvements. I imagine +<code class="computeroutput">bzip2</code> will perform best on +machines with very large caches.</p> +</div> +<div class="sect1" lang="en"> +<div class="titlepage"><div><div><h2 class="title" style="clear: both"> +<a name="caveats"></a>2.8. CAVEATS</h2></div></div></div> +<p>I/O error messages are not as helpful as they could be. +<code class="computeroutput">bzip2</code> tries hard to detect I/O +errors and exit cleanly, but the details of what the problem is +sometimes seem rather misleading.</p> +<p>This manual page pertains to version 1.0.5 of +<code class="computeroutput">bzip2</code>. Compressed data created by +this version is entirely forwards and backwards compatible with the +previous public releases, versions 0.1pl2, 0.9.0 and 0.9.5, 1.0.0, +1.0.1, 1.0.2 and 1.0.3, but with the following exception: 0.9.0 and +above can correctly decompress multiple concatenated compressed files. +0.1pl2 cannot do this; it will stop after decompressing just the first +file in the stream.</p> +<p><code class="computeroutput">bzip2recover</code> versions +prior to 1.0.2 used 32-bit integers to represent bit positions in +compressed files, so it could not handle compressed files more +than 512 megabytes long. Versions 1.0.2 and above use 64-bit ints +on some platforms which support them (GNU supported targets, and +Windows). To establish whether or not +<code class="computeroutput">bzip2recover</code> was built with such +a limitation, run it without arguments. In any event you can +build yourself an unlimited version if you can recompile it with +<code class="computeroutput">MaybeUInt64</code> set to be an +unsigned 64-bit integer.</p> +</div> +<div class="sect1" lang="en"> +<div class="titlepage"><div><div><h2 class="title" style="clear: both"> +<a name="author"></a>2.9. AUTHOR</h2></div></div></div> +<p>Julian Seward, +<code class="computeroutput">jseward@bzip.org</code></p> +<p>The ideas embodied in +<code class="computeroutput">bzip2</code> are due to (at least) the +following people: Michael Burrows and David Wheeler (for the +block sorting transformation), David Wheeler (again, for the +Huffman coder), Peter Fenwick (for the structured coding model in +the original <code class="computeroutput">bzip</code>, and many +refinements), and Alistair Moffat, Radford Neal and Ian Witten +(for the arithmetic coder in the original +<code class="computeroutput">bzip</code>). I am much indebted for +their help, support and advice. See the manual in the source +distribution for pointers to sources of documentation. Christian +von Roques encouraged me to look for faster sorting algorithms, +so as to speed up compression. Bela Lubkin encouraged me to +improve the worst-case compression performance. +Donna Robinson XMLised the documentation. +Many people sent +patches, helped with portability problems, lent machines, gave +advice and were generally helpful.</p> +</div> +</div> +<div class="chapter" lang="en"> +<div class="titlepage"><div><div><h2 class="title"> +<a name="libprog"></a>3. +Programming with <code class="computeroutput">libbzip2</code> +</h2></div></div></div> +<div class="toc"> +<p><b>Table of Contents</b></p> +<dl> +<dt><span class="sect1"><a href="#top-level">3.1. Top-level structure</a></span></dt> +<dd><dl> +<dt><span class="sect2"><a href="#ll-summary">3.1.1. Low-level summary</a></span></dt> +<dt><span class="sect2"><a href="#hl-summary">3.1.2. High-level summary</a></span></dt> +<dt><span class="sect2"><a href="#util-fns-summary">3.1.3. Utility functions summary</a></span></dt> +</dl></dd> +<dt><span class="sect1"><a href="#err-handling">3.2. Error handling</a></span></dt> +<dt><span class="sect1"><a href="#low-level">3.3. Low-level interface</a></span></dt> +<dd><dl> +<dt><span class="sect2"><a href="#bzcompress-init">3.3.1. <code class="computeroutput">BZ2_bzCompressInit</code></a></span></dt> +<dt><span class="sect2"><a href="#bzCompress">3.3.2. <code class="computeroutput">BZ2_bzCompress</code></a></span></dt> +<dt><span class="sect2"><a href="#bzCompress-end">3.3.3. <code class="computeroutput">BZ2_bzCompressEnd</code></a></span></dt> +<dt><span class="sect2"><a href="#bzDecompress-init">3.3.4. <code class="computeroutput">BZ2_bzDecompressInit</code></a></span></dt> +<dt><span class="sect2"><a href="#bzDecompress">3.3.5. <code class="computeroutput">BZ2_bzDecompress</code></a></span></dt> +<dt><span class="sect2"><a href="#bzDecompress-end">3.3.6. <code class="computeroutput">BZ2_bzDecompressEnd</code></a></span></dt> +</dl></dd> +<dt><span class="sect1"><a href="#hl-interface">3.4. High-level interface</a></span></dt> +<dd><dl> +<dt><span class="sect2"><a href="#bzreadopen">3.4.1. <code class="computeroutput">BZ2_bzReadOpen</code></a></span></dt> +<dt><span class="sect2"><a href="#bzread">3.4.2. <code class="computeroutput">BZ2_bzRead</code></a></span></dt> +<dt><span class="sect2"><a href="#bzreadgetunused">3.4.3. <code class="computeroutput">BZ2_bzReadGetUnused</code></a></span></dt> +<dt><span class="sect2"><a href="#bzreadclose">3.4.4. <code class="computeroutput">BZ2_bzReadClose</code></a></span></dt> +<dt><span class="sect2"><a href="#bzwriteopen">3.4.5. <code class="computeroutput">BZ2_bzWriteOpen</code></a></span></dt> +<dt><span class="sect2"><a href="#bzwrite">3.4.6. <code class="computeroutput">BZ2_bzWrite</code></a></span></dt> +<dt><span class="sect2"><a href="#bzwriteclose">3.4.7. <code class="computeroutput">BZ2_bzWriteClose</code></a></span></dt> +<dt><span class="sect2"><a href="#embed">3.4.8. Handling embedded compressed data streams</a></span></dt> +<dt><span class="sect2"><a href="#std-rdwr">3.4.9. Standard file-reading/writing code</a></span></dt> +</dl></dd> +<dt><span class="sect1"><a href="#util-fns">3.5. Utility functions</a></span></dt> +<dd><dl> +<dt><span class="sect2"><a href="#bzbufftobuffcompress">3.5.1. <code class="computeroutput">BZ2_bzBuffToBuffCompress</code></a></span></dt> +<dt><span class="sect2"><a href="#bzbufftobuffdecompress">3.5.2. <code class="computeroutput">BZ2_bzBuffToBuffDecompress</code></a></span></dt> +</dl></dd> +<dt><span class="sect1"><a href="#zlib-compat">3.6. <code class="computeroutput">zlib</code> compatibility functions</a></span></dt> +<dt><span class="sect1"><a href="#stdio-free">3.7. Using the library in a <code class="computeroutput">stdio</code>-free environment</a></span></dt> +<dd><dl> +<dt><span class="sect2"><a href="#stdio-bye">3.7.1. Getting rid of <code class="computeroutput">stdio</code></a></span></dt> +<dt><span class="sect2"><a href="#critical-error">3.7.2. Critical error handling</a></span></dt> +</dl></dd> +<dt><span class="sect1"><a href="#win-dll">3.8. Making a Windows DLL</a></span></dt> +</dl> +</div> +<p>This chapter describes the programming interface to +<code class="computeroutput">libbzip2</code>.</p> +<p>For general background information, particularly about +memory use and performance aspects, you'd be well advised to read +<a href="#using">How to use bzip2</a> as well.</p> +<div class="sect1" lang="en"> +<div class="titlepage"><div><div><h2 class="title" style="clear: both"> +<a name="top-level"></a>3.1. Top-level structure</h2></div></div></div> +<p><code class="computeroutput">libbzip2</code> is a flexible +library for compressing and decompressing data in the +<code class="computeroutput">bzip2</code> data format. Although +packaged as a single entity, it helps to regard the library as +three separate parts: the low level interface, and the high level +interface, and some utility functions.</p> +<p>The structure of +<code class="computeroutput">libbzip2</code>'s interfaces is similar +to that of Jean-loup Gailly's and Mark Adler's excellent +<code class="computeroutput">zlib</code> library.</p> +<p>All externally visible symbols have names beginning +<code class="computeroutput">BZ2_</code>. This is new in version +1.0. The intention is to minimise pollution of the namespaces of +library clients.</p> +<p>To use any part of the library, you need to +<code class="computeroutput">#include <bzlib.h></code> +into your sources.</p> +<div class="sect2" lang="en"> +<div class="titlepage"><div><div><h3 class="title"> +<a name="ll-summary"></a>3.1.1. Low-level summary</h3></div></div></div> +<p>This interface provides services for compressing and +decompressing data in memory. There's no provision for dealing +with files, streams or any other I/O mechanisms, just straight +memory-to-memory work. In fact, this part of the library can be +compiled without inclusion of +<code class="computeroutput">stdio.h</code>, which may be helpful +for embedded applications.</p> +<p>The low-level part of the library has no global variables +and is therefore thread-safe.</p> +<p>Six routines make up the low level interface: +<code class="computeroutput">BZ2_bzCompressInit</code>, +<code class="computeroutput">BZ2_bzCompress</code>, and +<code class="computeroutput">BZ2_bzCompressEnd</code> for +compression, and a corresponding trio +<code class="computeroutput">BZ2_bzDecompressInit</code>, +<code class="computeroutput">BZ2_bzDecompress</code> and +<code class="computeroutput">BZ2_bzDecompressEnd</code> for +decompression. The <code class="computeroutput">*Init</code> +functions allocate memory for compression/decompression and do +other initialisations, whilst the +<code class="computeroutput">*End</code> functions close down +operations and release memory.</p> +<p>The real work is done by +<code class="computeroutput">BZ2_bzCompress</code> and +<code class="computeroutput">BZ2_bzDecompress</code>. These +compress and decompress data from a user-supplied input buffer to +a user-supplied output buffer. These buffers can be any size; +arbitrary quantities of data are handled by making repeated calls +to these functions. This is a flexible mechanism allowing a +consumer-pull style of activity, or producer-push, or a mixture +of both.</p> +</div> +<div class="sect2" lang="en"> +<div class="titlepage"><div><div><h3 class="title"> +<a name="hl-summary"></a>3.1.2. High-level summary</h3></div></div></div> +<p>This interface provides some handy wrappers around the +low-level interface to facilitate reading and writing +<code class="computeroutput">bzip2</code> format files +(<code class="computeroutput">.bz2</code> files). The routines +provide hooks to facilitate reading files in which the +<code class="computeroutput">bzip2</code> data stream is embedded +within some larger-scale file structure, or where there are +multiple <code class="computeroutput">bzip2</code> data streams +concatenated end-to-end.</p> +<p>For reading files, +<code class="computeroutput">BZ2_bzReadOpen</code>, +<code class="computeroutput">BZ2_bzRead</code>, +<code class="computeroutput">BZ2_bzReadClose</code> and +<code class="computeroutput">BZ2_bzReadGetUnused</code> are +supplied. For writing files, +<code class="computeroutput">BZ2_bzWriteOpen</code>, +<code class="computeroutput">BZ2_bzWrite</code> and +<code class="computeroutput">BZ2_bzWriteFinish</code> are +available.</p> +<p>As with the low-level library, no global variables are used +so the library is per se thread-safe. However, if I/O errors +occur whilst reading or writing the underlying compressed files, +you may have to consult <code class="computeroutput">errno</code> to +determine the cause of the error. In that case, you'd need a C +library which correctly supports +<code class="computeroutput">errno</code> in a multithreaded +environment.</p> +<p>To make the library a little simpler and more portable, +<code class="computeroutput">BZ2_bzReadOpen</code> and +<code class="computeroutput">BZ2_bzWriteOpen</code> require you to +pass them file handles (<code class="computeroutput">FILE*</code>s) +which have previously been opened for reading or writing +respectively. That avoids portability problems associated with +file operations and file attributes, whilst not being much of an +imposition on the programmer.</p> +</div> +<div class="sect2" lang="en"> +<div class="titlepage"><div><div><h3 class="title"> +<a name="util-fns-summary"></a>3.1.3. Utility functions summary</h3></div></div></div> +<p>For very simple needs, +<code class="computeroutput">BZ2_bzBuffToBuffCompress</code> and +<code class="computeroutput">BZ2_bzBuffToBuffDecompress</code> are +provided. These compress data in memory from one buffer to +another buffer in a single function call. You should assess +whether these functions fulfill your memory-to-memory +compression/decompression requirements before investing effort in +understanding the more general but more complex low-level +interface.</p> +<p>Yoshioka Tsuneo +(<code class="computeroutput">tsuneo@rr.iij4u.or.jp</code>) has +contributed some functions to give better +<code class="computeroutput">zlib</code> compatibility. These +functions are <code class="computeroutput">BZ2_bzopen</code>, +<code class="computeroutput">BZ2_bzread</code>, +<code class="computeroutput">BZ2_bzwrite</code>, +<code class="computeroutput">BZ2_bzflush</code>, +<code class="computeroutput">BZ2_bzclose</code>, +<code class="computeroutput">BZ2_bzerror</code> and +<code class="computeroutput">BZ2_bzlibVersion</code>. You may find +these functions more convenient for simple file reading and +writing, than those in the high-level interface. These functions +are not (yet) officially part of the library, and are minimally +documented here. If they break, you get to keep all the pieces. +I hope to document them properly when time permits.</p> +<p>Yoshioka also contributed modifications to allow the +library to be built as a Windows DLL.</p> +</div> +</div> +<div class="sect1" lang="en"> +<div class="titlepage"><div><div><h2 class="title" style="clear: both"> +<a name="err-handling"></a>3.2. Error handling</h2></div></div></div> +<p>The library is designed to recover cleanly in all +situations, including the worst-case situation of decompressing +random data. I'm not 100% sure that it can always do this, so +you might want to add a signal handler to catch segmentation +violations during decompression if you are feeling especially +paranoid. I would be interested in hearing more about the +robustness of the library to corrupted compressed data.</p> +<p>Version 1.0.3 more robust in this respect than any +previous version. Investigations with Valgrind (a tool for detecting +problems with memory management) indicate +that, at least for the few files I tested, all single-bit errors +in the decompressed data are caught properly, with no +segmentation faults, no uses of uninitialised data, no out of +range reads or writes, and no infinite looping in the decompressor. +So it's certainly pretty robust, although +I wouldn't claim it to be totally bombproof.</p> +<p>The file <code class="computeroutput">bzlib.h</code> contains +all definitions needed to use the library. In particular, you +should definitely not include +<code class="computeroutput">bzlib_private.h</code>.</p> +<p>In <code class="computeroutput">bzlib.h</code>, the various +return values are defined. The following list is not intended as +an exhaustive description of the circumstances in which a given +value may be returned -- those descriptions are given later. +Rather, it is intended to convey the rough meaning of each return +value. The first five actions are normal and not intended to +denote an error situation.</p> +<div class="variablelist"><dl> +<dt><span class="term"><code class="computeroutput">BZ_OK</code></span></dt> +<dd><p>The requested action was completed + successfully.</p></dd> +<dt><span class="term"><code class="computeroutput">BZ_RUN_OK, BZ_FLUSH_OK, + BZ_FINISH_OK</code></span></dt> +<dd><p>In + <code class="computeroutput">BZ2_bzCompress</code>, the requested + flush/finish/nothing-special action was completed + successfully.</p></dd> +<dt><span class="term"><code class="computeroutput">BZ_STREAM_END</code></span></dt> +<dd><p>Compression of data was completed, or the + logical stream end was detected during + decompression.</p></dd> +</dl></div> +<p>The following return values indicate an error of some +kind.</p> +<div class="variablelist"><dl> +<dt><span class="term"><code class="computeroutput">BZ_CONFIG_ERROR</code></span></dt> +<dd><p>Indicates that the library has been improperly + compiled on your platform -- a major configuration error. + Specifically, it means that + <code class="computeroutput">sizeof(char)</code>, + <code class="computeroutput">sizeof(short)</code> and + <code class="computeroutput">sizeof(int)</code> are not 1, 2 and + 4 respectively, as they should be. Note that the library + should still work properly on 64-bit platforms which follow + the LP64 programming model -- that is, where + <code class="computeroutput">sizeof(long)</code> and + <code class="computeroutput">sizeof(void*)</code> are 8. Under + LP64, <code class="computeroutput">sizeof(int)</code> is still 4, + so <code class="computeroutput">libbzip2</code>, which doesn't + use the <code class="computeroutput">long</code> type, is + OK.</p></dd> +<dt><span class="term"><code class="computeroutput">BZ_SEQUENCE_ERROR</code></span></dt> +<dd><p>When using the library, it is important to call + the functions in the correct sequence and with data structures + (buffers etc) in the correct states. + <code class="computeroutput">libbzip2</code> checks as much as it + can to ensure this is happening, and returns + <code class="computeroutput">BZ_SEQUENCE_ERROR</code> if not. + Code which complies precisely with the function semantics, as + detailed below, should never receive this value; such an event + denotes buggy code which you should + investigate.</p></dd> +<dt><span class="term"><code class="computeroutput">BZ_PARAM_ERROR</code></span></dt> +<dd><p>Returned when a parameter to a function call is + out of range or otherwise manifestly incorrect. As with + <code class="computeroutput">BZ_SEQUENCE_ERROR</code>, this + denotes a bug in the client code. The distinction between + <code class="computeroutput">BZ_PARAM_ERROR</code> and + <code class="computeroutput">BZ_SEQUENCE_ERROR</code> is a bit + hazy, but still worth making.</p></dd> +<dt><span class="term"><code class="computeroutput">BZ_MEM_ERROR</code></span></dt> +<dd><p>Returned when a request to allocate memory + failed. Note that the quantity of memory needed to decompress + a stream cannot be determined until the stream's header has + been read. So + <code class="computeroutput">BZ2_bzDecompress</code> and + <code class="computeroutput">BZ2_bzRead</code> may return + <code class="computeroutput">BZ_MEM_ERROR</code> even though some + of the compressed data has been read. The same is not true + for compression; once + <code class="computeroutput">BZ2_bzCompressInit</code> or + <code class="computeroutput">BZ2_bzWriteOpen</code> have + successfully completed, + <code class="computeroutput">BZ_MEM_ERROR</code> cannot + occur.</p></dd> +<dt><span class="term"><code class="computeroutput">BZ_DATA_ERROR</code></span></dt> +<dd><p>Returned when a data integrity error is + detected during decompression. Most importantly, this means + when stored and computed CRCs for the data do not match. This + value is also returned upon detection of any other anomaly in + the compressed data.</p></dd> +<dt><span class="term"><code class="computeroutput">BZ_DATA_ERROR_MAGIC</code></span></dt> +<dd><p>As a special case of + <code class="computeroutput">BZ_DATA_ERROR</code>, it is + sometimes useful to know when the compressed stream does not + start with the correct magic bytes (<code class="computeroutput">'B' 'Z' + 'h'</code>).</p></dd> +<dt><span class="term"><code class="computeroutput">BZ_IO_ERROR</code></span></dt> +<dd><p>Returned by + <code class="computeroutput">BZ2_bzRead</code> and + <code class="computeroutput">BZ2_bzWrite</code> when there is an + error reading or writing in the compressed file, and by + <code class="computeroutput">BZ2_bzReadOpen</code> and + <code class="computeroutput">BZ2_bzWriteOpen</code> for attempts + to use a file for which the error indicator (viz, + <code class="computeroutput">ferror(f)</code>) is set. On + receipt of <code class="computeroutput">BZ_IO_ERROR</code>, the + caller should consult <code class="computeroutput">errno</code> + and/or <code class="computeroutput">perror</code> to acquire + operating-system specific information about the + problem.</p></dd> +<dt><span class="term"><code class="computeroutput">BZ_UNEXPECTED_EOF</code></span></dt> +<dd><p>Returned by + <code class="computeroutput">BZ2_bzRead</code> when the + compressed file finishes before the logical end of stream is + detected.</p></dd> +<dt><span class="term"><code class="computeroutput">BZ_OUTBUFF_FULL</code></span></dt> +<dd><p>Returned by + <code class="computeroutput">BZ2_bzBuffToBuffCompress</code> and + <code class="computeroutput">BZ2_bzBuffToBuffDecompress</code> to + indicate that the output data will not fit into the output + buffer provided.</p></dd> +</dl></div> +</div> +<div class="sect1" lang="en"> +<div class="titlepage"><div><div><h2 class="title" style="clear: both"> +<a name="low-level"></a>3.3. Low-level interface</h2></div></div></div> +<div class="sect2" lang="en"> +<div class="titlepage"><div><div><h3 class="title"> +<a name="bzcompress-init"></a>3.3.1. <code class="computeroutput">BZ2_bzCompressInit</code></h3></div></div></div> +<pre class="programlisting">typedef struct { + char *next_in; + unsigned int avail_in; + unsigned int total_in_lo32; + unsigned int total_in_hi32; + + char *next_out; + unsigned int avail_out; + unsigned int total_out_lo32; + unsigned int total_out_hi32; + + void *state; + + void *(*bzalloc)(void *,int,int); + void (*bzfree)(void *,void *); + void *opaque; +} bz_stream; + +int BZ2_bzCompressInit ( bz_stream *strm, + int blockSize100k, + int verbosity, + int workFactor );</pre> +<p>Prepares for compression. The +<code class="computeroutput">bz_stream</code> structure holds all +data pertaining to the compression activity. A +<code class="computeroutput">bz_stream</code> structure should be +allocated and initialised prior to the call. The fields of +<code class="computeroutput">bz_stream</code> comprise the entirety +of the user-visible data. <code class="computeroutput">state</code> +is a pointer to the private data structures required for +compression.</p> +<p>Custom memory allocators are supported, via fields +<code class="computeroutput">bzalloc</code>, +<code class="computeroutput">bzfree</code>, and +<code class="computeroutput">opaque</code>. The value +<code class="computeroutput">opaque</code> is passed to as the first +argument to all calls to <code class="computeroutput">bzalloc</code> +and <code class="computeroutput">bzfree</code>, but is otherwise +ignored by the library. The call <code class="computeroutput">bzalloc ( +opaque, n, m )</code> is expected to return a pointer +<code class="computeroutput">p</code> to <code class="computeroutput">n * +m</code> bytes of memory, and <code class="computeroutput">bzfree ( +opaque, p )</code> should free that memory.</p> +<p>If you don't want to use a custom memory allocator, set +<code class="computeroutput">bzalloc</code>, +<code class="computeroutput">bzfree</code> and +<code class="computeroutput">opaque</code> to +<code class="computeroutput">NULL</code>, and the library will then +use the standard <code class="computeroutput">malloc</code> / +<code class="computeroutput">free</code> routines.</p> +<p>Before calling +<code class="computeroutput">BZ2_bzCompressInit</code>, fields +<code class="computeroutput">bzalloc</code>, +<code class="computeroutput">bzfree</code> and +<code class="computeroutput">opaque</code> should be filled +appropriately, as just described. Upon return, the internal +state will have been allocated and initialised, and +<code class="computeroutput">total_in_lo32</code>, +<code class="computeroutput">total_in_hi32</code>, +<code class="computeroutput">total_out_lo32</code> and +<code class="computeroutput">total_out_hi32</code> will have been +set to zero. These four fields are used by the library to inform +the caller of the total amount of data passed into and out of the +library, respectively. You should not try to change them. As of +version 1.0, 64-bit counts are maintained, even on 32-bit +platforms, using the <code class="computeroutput">_hi32</code> +fields to store the upper 32 bits of the count. So, for example, +the total amount of data in is <code class="computeroutput">(total_in_hi32 +<< 32) + total_in_lo32</code>.</p> +<p>Parameter <code class="computeroutput">blockSize100k</code> +specifies the block size to be used for compression. It should +be a value between 1 and 9 inclusive, and the actual block size +used is 100000 x this figure. 9 gives the best compression but +takes most memory.</p> +<p>Parameter <code class="computeroutput">verbosity</code> should +be set to a number between 0 and 4 inclusive. 0 is silent, and +greater numbers give increasingly verbose monitoring/debugging +output. If the library has been compiled with +<code class="computeroutput">-DBZ_NO_STDIO</code>, no such output +will appear for any verbosity setting.</p> +<p>Parameter <code class="computeroutput">workFactor</code> +controls how the compression phase behaves when presented with +worst case, highly repetitive, input data. If compression runs +into difficulties caused by repetitive data, the library switches +from the standard sorting algorithm to a fallback algorithm. The +fallback is slower than the standard algorithm by perhaps a +factor of three, but always behaves reasonably, no matter how bad +the input.</p> +<p>Lower values of <code class="computeroutput">workFactor</code> +reduce the amount of effort the standard algorithm will expend +before resorting to the fallback. You should set this parameter +carefully; too low, and many inputs will be handled by the +fallback algorithm and so compress rather slowly, too high, and +your average-to-worst case compression times can become very +large. The default value of 30 gives reasonable behaviour over a +wide range of circumstances.</p> +<p>Allowable values range from 0 to 250 inclusive. 0 is a +special case, equivalent to using the default value of 30.</p> +<p>Note that the compressed output generated is the same +regardless of whether or not the fallback algorithm is +used.</p> +<p>Be aware also that this parameter may disappear entirely in +future versions of the library. In principle it should be +possible to devise a good way to automatically choose which +algorithm to use. Such a mechanism would render the parameter +obsolete.</p> +<p>Possible return values:</p> +<pre class="programlisting">BZ_CONFIG_ERROR + if the library has been mis-compiled +BZ_PARAM_ERROR + if strm is NULL + or blockSize < 1 or blockSize > 9 + or verbosity < 0 or verbosity > 4 + or workFactor < 0 or workFactor > 250 +BZ_MEM_ERROR + if not enough memory is available +BZ_OK + otherwise</pre> +<p>Allowable next actions:</p> +<pre class="programlisting">BZ2_bzCompress + if BZ_OK is returned + no specific action needed in case of error</pre> +</div> +<div class="sect2" lang="en"> +<div class="titlepage"><div><div><h3 class="title"> +<a name="bzCompress"></a>3.3.2. <code class="computeroutput">BZ2_bzCompress</code></h3></div></div></div> +<pre class="programlisting">int BZ2_bzCompress ( bz_stream *strm, int action );</pre> +<p>Provides more input and/or output buffer space for the +library. The caller maintains input and output buffers, and +calls <code class="computeroutput">BZ2_bzCompress</code> to transfer +data between them.</p> +<p>Before each call to +<code class="computeroutput">BZ2_bzCompress</code>, +<code class="computeroutput">next_in</code> should point at the data +to be compressed, and <code class="computeroutput">avail_in</code> +should indicate how many bytes the library may read. +<code class="computeroutput">BZ2_bzCompress</code> updates +<code class="computeroutput">next_in</code>, +<code class="computeroutput">avail_in</code> and +<code class="computeroutput">total_in</code> to reflect the number +of bytes it has read.</p> +<p>Similarly, <code class="computeroutput">next_out</code> should +point to a buffer in which the compressed data is to be placed, +with <code class="computeroutput">avail_out</code> indicating how +much output space is available. +<code class="computeroutput">BZ2_bzCompress</code> updates +<code class="computeroutput">next_out</code>, +<code class="computeroutput">avail_out</code> and +<code class="computeroutput">total_out</code> to reflect the number +of bytes output.</p> +<p>You may provide and remove as little or as much data as you +like on each call of +<code class="computeroutput">BZ2_bzCompress</code>. In the limit, +it is acceptable to supply and remove data one byte at a time, +although this would be terribly inefficient. You should always +ensure that at least one byte of output space is available at +each call.</p> +<p>A second purpose of +<code class="computeroutput">BZ2_bzCompress</code> is to request a +change of mode of the compressed stream.</p> +<p>Conceptually, a compressed stream can be in one of four +states: IDLE, RUNNING, FLUSHING and FINISHING. Before +initialisation +(<code class="computeroutput">BZ2_bzCompressInit</code>) and after +termination (<code class="computeroutput">BZ2_bzCompressEnd</code>), +a stream is regarded as IDLE.</p> +<p>Upon initialisation +(<code class="computeroutput">BZ2_bzCompressInit</code>), the stream +is placed in the RUNNING state. Subsequent calls to +<code class="computeroutput">BZ2_bzCompress</code> should pass +<code class="computeroutput">BZ_RUN</code> as the requested action; +other actions are illegal and will result in +<code class="computeroutput">BZ_SEQUENCE_ERROR</code>.</p> +<p>At some point, the calling program will have provided all +the input data it wants to. It will then want to finish up -- in +effect, asking the library to process any data it might have +buffered internally. In this state, +<code class="computeroutput">BZ2_bzCompress</code> will no longer +attempt to read data from +<code class="computeroutput">next_in</code>, but it will want to +write data to <code class="computeroutput">next_out</code>. Because +the output buffer supplied by the user can be arbitrarily small, +the finishing-up operation cannot necessarily be done with a +single call of +<code class="computeroutput">BZ2_bzCompress</code>.</p> +<p>Instead, the calling program passes +<code class="computeroutput">BZ_FINISH</code> as an action to +<code class="computeroutput">BZ2_bzCompress</code>. This changes +the stream's state to FINISHING. Any remaining input (ie, +<code class="computeroutput">next_in[0 .. avail_in-1]</code>) is +compressed and transferred to the output buffer. To do this, +<code class="computeroutput">BZ2_bzCompress</code> must be called +repeatedly until all the output has been consumed. At that +point, <code class="computeroutput">BZ2_bzCompress</code> returns +<code class="computeroutput">BZ_STREAM_END</code>, and the stream's +state is set back to IDLE. +<code class="computeroutput">BZ2_bzCompressEnd</code> should then be +called.</p> +<p>Just to make sure the calling program does not cheat, the +library makes a note of <code class="computeroutput">avail_in</code> +at the time of the first call to +<code class="computeroutput">BZ2_bzCompress</code> which has +<code class="computeroutput">BZ_FINISH</code> as an action (ie, at +the time the program has announced its intention to not supply +any more input). By comparing this value with that of +<code class="computeroutput">avail_in</code> over subsequent calls +to <code class="computeroutput">BZ2_bzCompress</code>, the library +can detect any attempts to slip in more data to compress. Any +calls for which this is detected will return +<code class="computeroutput">BZ_SEQUENCE_ERROR</code>. This +indicates a programming mistake which should be corrected.</p> +<p>Instead of asking to finish, the calling program may ask +<code class="computeroutput">BZ2_bzCompress</code> to take all the +remaining input, compress it and terminate the current +(Burrows-Wheeler) compression block. This could be useful for +error control purposes. The mechanism is analogous to that for +finishing: call <code class="computeroutput">BZ2_bzCompress</code> +with an action of <code class="computeroutput">BZ_FLUSH</code>, +remove output data, and persist with the +<code class="computeroutput">BZ_FLUSH</code> action until the value +<code class="computeroutput">BZ_RUN</code> is returned. As with +finishing, <code class="computeroutput">BZ2_bzCompress</code> +detects any attempt to provide more input data once the flush has +begun.</p> +<p>Once the flush is complete, the stream returns to the +normal RUNNING state.</p> +<p>This all sounds pretty complex, but isn't really. Here's a +table which shows which actions are allowable in each state, what +action will be taken, what the next state is, and what the +non-error return values are. Note that you can't explicitly ask +what state the stream is in, but nor do you need to -- it can be +inferred from the values returned by +<code class="computeroutput">BZ2_bzCompress</code>.</p> +<pre class="programlisting">IDLE/any + Illegal. IDLE state only exists after BZ2_bzCompressEnd or + before BZ2_bzCompressInit. + Return value = BZ_SEQUENCE_ERROR + +RUNNING/BZ_RUN + Compress from next_in to next_out as much as possible. + Next state = RUNNING + Return value = BZ_RUN_OK + +RUNNING/BZ_FLUSH + Remember current value of next_in. Compress from next_in + to next_out as much as possible, but do not accept any more input. + Next state = FLUSHING + Return value = BZ_FLUSH_OK + +RUNNING/BZ_FINISH + Remember current value of next_in. Compress from next_in + to next_out as much as possible, but do not accept any more input. + Next state = FINISHING + Return value = BZ_FINISH_OK + +FLUSHING/BZ_FLUSH + Compress from next_in to next_out as much as possible, + but do not accept any more input. + If all the existing input has been used up and all compressed + output has been removed + Next state = RUNNING; Return value = BZ_RUN_OK + else + Next state = FLUSHING; Return value = BZ_FLUSH_OK + +FLUSHING/other + Illegal. + Return value = BZ_SEQUENCE_ERROR + +FINISHING/BZ_FINISH + Compress from next_in to next_out as much as possible, + but to not accept any more input. + If all the existing input has been used up and all compressed + output has been removed + Next state = IDLE; Return value = BZ_STREAM_END + else + Next state = FINISHING; Return value = BZ_FINISH_OK + +FINISHING/other + Illegal. + Return value = BZ_SEQUENCE_ERROR</pre> +<p>That still looks complicated? Well, fair enough. The +usual sequence of calls for compressing a load of data is:</p> +<div class="orderedlist"><ol type="1"> +<li><p>Get started with + <code class="computeroutput">BZ2_bzCompressInit</code>.</p></li> +<li><p>Shovel data in and shlurp out its compressed form + using zero or more calls of + <code class="computeroutput">BZ2_bzCompress</code> with action = + <code class="computeroutput">BZ_RUN</code>.</p></li> +<li><p>Finish up. Repeatedly call + <code class="computeroutput">BZ2_bzCompress</code> with action = + <code class="computeroutput">BZ_FINISH</code>, copying out the + compressed output, until + <code class="computeroutput">BZ_STREAM_END</code> is + returned.</p></li> +<li><p>Close up and go home. Call + <code class="computeroutput">BZ2_bzCompressEnd</code>.</p></li> +</ol></div> +<p>If the data you want to compress fits into your input +buffer all at once, you can skip the calls of +<code class="computeroutput">BZ2_bzCompress ( ..., BZ_RUN )</code> +and just do the <code class="computeroutput">BZ2_bzCompress ( ..., BZ_FINISH +)</code> calls.</p> +<p>All required memory is allocated by +<code class="computeroutput">BZ2_bzCompressInit</code>. The +compression library can accept any data at all (obviously). So +you shouldn't get any error return values from the +<code class="computeroutput">BZ2_bzCompress</code> calls. If you +do, they will be +<code class="computeroutput">BZ_SEQUENCE_ERROR</code>, and indicate +a bug in your programming.</p> +<p>Trivial other possible return values:</p> +<pre class="programlisting">BZ_PARAM_ERROR + if strm is NULL, or strm->s is NULL</pre> +</div> +<div class="sect2" lang="en"> +<div class="titlepage"><div><div><h3 class="title"> +<a name="bzCompress-end"></a>3.3.3. <code class="computeroutput">BZ2_bzCompressEnd</code></h3></div></div></div> +<pre class="programlisting">int BZ2_bzCompressEnd ( bz_stream *strm );</pre> +<p>Releases all memory associated with a compression +stream.</p> +<p>Possible return values:</p> +<pre class="programlisting">BZ_PARAM_ERROR if strm is NULL or strm->s is NULL +BZ_OK otherwise</pre> +</div> +<div class="sect2" lang="en"> +<div class="titlepage"><div><div><h3 class="title"> +<a name="bzDecompress-init"></a>3.3.4. <code class="computeroutput">BZ2_bzDecompressInit</code></h3></div></div></div> +<pre class="programlisting">int BZ2_bzDecompressInit ( bz_stream *strm, int verbosity, int small );</pre> +<p>Prepares for decompression. As with +<code class="computeroutput">BZ2_bzCompressInit</code>, a +<code class="computeroutput">bz_stream</code> record should be +allocated and initialised before the call. Fields +<code class="computeroutput">bzalloc</code>, +<code class="computeroutput">bzfree</code> and +<code class="computeroutput">opaque</code> should be set if a custom +memory allocator is required, or made +<code class="computeroutput">NULL</code> for the normal +<code class="computeroutput">malloc</code> / +<code class="computeroutput">free</code> routines. Upon return, the +internal state will have been initialised, and +<code class="computeroutput">total_in</code> and +<code class="computeroutput">total_out</code> will be zero.</p> +<p>For the meaning of parameter +<code class="computeroutput">verbosity</code>, see +<code class="computeroutput">BZ2_bzCompressInit</code>.</p> +<p>If <code class="computeroutput">small</code> is nonzero, the +library will use an alternative decompression algorithm which +uses less memory but at the cost of decompressing more slowly +(roughly speaking, half the speed, but the maximum memory +requirement drops to around 2300k). See <a href="#using">How to use bzip2</a> +for more information on memory management.</p> +<p>Note that the amount of memory needed to decompress a +stream cannot be determined until the stream's header has been +read, so even if +<code class="computeroutput">BZ2_bzDecompressInit</code> succeeds, a +subsequent <code class="computeroutput">BZ2_bzDecompress</code> +could fail with +<code class="computeroutput">BZ_MEM_ERROR</code>.</p> +<p>Possible return values:</p> +<pre class="programlisting">BZ_CONFIG_ERROR + if the library has been mis-compiled +BZ_PARAM_ERROR + if ( small != 0 && small != 1 ) + or (verbosity <; 0 || verbosity > 4) +BZ_MEM_ERROR + if insufficient memory is available</pre> +<p>Allowable next actions:</p> +<pre class="programlisting">BZ2_bzDecompress + if BZ_OK was returned + no specific action required in case of error</pre> +</div> +<div class="sect2" lang="en"> +<div class="titlepage"><div><div><h3 class="title"> +<a name="bzDecompress"></a>3.3.5. <code class="computeroutput">BZ2_bzDecompress</code></h3></div></div></div> +<pre class="programlisting">int BZ2_bzDecompress ( bz_stream *strm );</pre> +<p>Provides more input and/out output buffer space for the +library. The caller maintains input and output buffers, and uses +<code class="computeroutput">BZ2_bzDecompress</code> to transfer +data between them.</p> +<p>Before each call to +<code class="computeroutput">BZ2_bzDecompress</code>, +<code class="computeroutput">next_in</code> should point at the +compressed data, and <code class="computeroutput">avail_in</code> +should indicate how many bytes the library may read. +<code class="computeroutput">BZ2_bzDecompress</code> updates +<code class="computeroutput">next_in</code>, +<code class="computeroutput">avail_in</code> and +<code class="computeroutput">total_in</code> to reflect the number +of bytes it has read.</p> +<p>Similarly, <code class="computeroutput">next_out</code> should +point to a buffer in which the uncompressed output is to be +placed, with <code class="computeroutput">avail_out</code> +indicating how much output space is available. +<code class="computeroutput">BZ2_bzCompress</code> updates +<code class="computeroutput">next_out</code>, +<code class="computeroutput">avail_out</code> and +<code class="computeroutput">total_out</code> to reflect the number +of bytes output.</p> +<p>You may provide and remove as little or as much data as you +like on each call of +<code class="computeroutput">BZ2_bzDecompress</code>. In the limit, +it is acceptable to supply and remove data one byte at a time, +although this would be terribly inefficient. You should always +ensure that at least one byte of output space is available at +each call.</p> +<p>Use of <code class="computeroutput">BZ2_bzDecompress</code> is +simpler than +<code class="computeroutput">BZ2_bzCompress</code>.</p> +<p>You should provide input and remove output as described +above, and repeatedly call +<code class="computeroutput">BZ2_bzDecompress</code> until +<code class="computeroutput">BZ_STREAM_END</code> is returned. +Appearance of <code class="computeroutput">BZ_STREAM_END</code> +denotes that <code class="computeroutput">BZ2_bzDecompress</code> +has detected the logical end of the compressed stream. +<code class="computeroutput">BZ2_bzDecompress</code> will not +produce <code class="computeroutput">BZ_STREAM_END</code> until all +output data has been placed into the output buffer, so once +<code class="computeroutput">BZ_STREAM_END</code> appears, you are +guaranteed to have available all the decompressed output, and +<code class="computeroutput">BZ2_bzDecompressEnd</code> can safely +be called.</p> +<p>If case of an error return value, you should call +<code class="computeroutput">BZ2_bzDecompressEnd</code> to clean up +and release memory.</p> +<p>Possible return values:</p> +<pre class="programlisting">BZ_PARAM_ERROR + if strm is NULL or strm->s is NULL + or strm->avail_out < 1 +BZ_DATA_ERROR + if a data integrity error is detected in the compressed stream +BZ_DATA_ERROR_MAGIC + if the compressed stream doesn't begin with the right magic bytes +BZ_MEM_ERROR + if there wasn't enough memory available +BZ_STREAM_END + if the logical end of the data stream was detected and all + output in has been consumed, eg s-->avail_out > 0 +BZ_OK + otherwise</pre> +<p>Allowable next actions:</p> +<pre class="programlisting">BZ2_bzDecompress + if BZ_OK was returned +BZ2_bzDecompressEnd + otherwise</pre> +</div> +<div class="sect2" lang="en"> +<div class="titlepage"><div><div><h3 class="title"> +<a name="bzDecompress-end"></a>3.3.6. <code class="computeroutput">BZ2_bzDecompressEnd</code></h3></div></div></div> +<pre class="programlisting">int BZ2_bzDecompressEnd ( bz_stream *strm );</pre> +<p>Releases all memory associated with a decompression +stream.</p> +<p>Possible return values:</p> +<pre class="programlisting">BZ_PARAM_ERROR + if strm is NULL or strm->s is NULL +BZ_OK + otherwise</pre> +<p>Allowable next actions:</p> +<pre class="programlisting"> None.</pre> +</div> +</div> +<div class="sect1" lang="en"> +<div class="titlepage"><div><div><h2 class="title" style="clear: both"> +<a name="hl-interface"></a>3.4. High-level interface</h2></div></div></div> +<p>This interface provides functions for reading and writing +<code class="computeroutput">bzip2</code> format files. First, some +general points.</p> +<div class="itemizedlist"><ul type="bullet"> +<li style="list-style-type: disc"><p>All of the functions take an + <code class="computeroutput">int*</code> first argument, + <code class="computeroutput">bzerror</code>. After each call, + <code class="computeroutput">bzerror</code> should be consulted + first to determine the outcome of the call. If + <code class="computeroutput">bzerror</code> is + <code class="computeroutput">BZ_OK</code>, the call completed + successfully, and only then should the return value of the + function (if any) be consulted. If + <code class="computeroutput">bzerror</code> is + <code class="computeroutput">BZ_IO_ERROR</code>, there was an + error reading/writing the underlying compressed file, and you + should then consult <code class="computeroutput">errno</code> / + <code class="computeroutput">perror</code> to determine the cause + of the difficulty. <code class="computeroutput">bzerror</code> + may also be set to various other values; precise details are + given on a per-function basis below.</p></li> +<li style="list-style-type: disc"><p>If <code class="computeroutput">bzerror</code> indicates + an error (ie, anything except + <code class="computeroutput">BZ_OK</code> and + <code class="computeroutput">BZ_STREAM_END</code>), you should + immediately call + <code class="computeroutput">BZ2_bzReadClose</code> (or + <code class="computeroutput">BZ2_bzWriteClose</code>, depending on + whether you are attempting to read or to write) to free up all + resources associated with the stream. Once an error has been + indicated, behaviour of all calls except + <code class="computeroutput">BZ2_bzReadClose</code> + (<code class="computeroutput">BZ2_bzWriteClose</code>) is + undefined. The implication is that (1) + <code class="computeroutput">bzerror</code> should be checked + after each call, and (2) if + <code class="computeroutput">bzerror</code> indicates an error, + <code class="computeroutput">BZ2_bzReadClose</code> + (<code class="computeroutput">BZ2_bzWriteClose</code>) should then + be called to clean up.</p></li> +<li style="list-style-type: disc"><p>The <code class="computeroutput">FILE*</code> arguments + passed to <code class="computeroutput">BZ2_bzReadOpen</code> / + <code class="computeroutput">BZ2_bzWriteOpen</code> should be set + to binary mode. Most Unix systems will do this by default, but + other platforms, including Windows and Mac, will not. If you + omit this, you may encounter problems when moving code to new + platforms.</p></li> +<li style="list-style-type: disc"><p>Memory allocation requests are handled by + <code class="computeroutput">malloc</code> / + <code class="computeroutput">free</code>. At present there is no + facility for user-defined memory allocators in the file I/O + functions (could easily be added, though).</p></li> +</ul></div> +<div class="sect2" lang="en"> +<div class="titlepage"><div><div><h3 class="title"> +<a name="bzreadopen"></a>3.4.1. <code class="computeroutput">BZ2_bzReadOpen</code></h3></div></div></div> +<pre class="programlisting">typedef void BZFILE; + +BZFILE *BZ2_bzReadOpen( int *bzerror, FILE *f, + int verbosity, int small, + void *unused, int nUnused );</pre> +<p>Prepare to read compressed data from file handle +<code class="computeroutput">f</code>. +<code class="computeroutput">f</code> should refer to a file which +has been opened for reading, and for which the error indicator +(<code class="computeroutput">ferror(f)</code>)is not set. If +<code class="computeroutput">small</code> is 1, the library will try +to decompress using less memory, at the expense of speed.</p> +<p>For reasons explained below, +<code class="computeroutput">BZ2_bzRead</code> will decompress the +<code class="computeroutput">nUnused</code> bytes starting at +<code class="computeroutput">unused</code>, before starting to read +from the file <code class="computeroutput">f</code>. At most +<code class="computeroutput">BZ_MAX_UNUSED</code> bytes may be +supplied like this. If this facility is not required, you should +pass <code class="computeroutput">NULL</code> and +<code class="computeroutput">0</code> for +<code class="computeroutput">unused</code> and +n<code class="computeroutput">Unused</code> respectively.</p> +<p>For the meaning of parameters +<code class="computeroutput">small</code> and +<code class="computeroutput">verbosity</code>, see +<code class="computeroutput">BZ2_bzDecompressInit</code>.</p> +<p>The amount of memory needed to decompress a file cannot be +determined until the file's header has been read. So it is +possible that <code class="computeroutput">BZ2_bzReadOpen</code> +returns <code class="computeroutput">BZ_OK</code> but a subsequent +call of <code class="computeroutput">BZ2_bzRead</code> will return +<code class="computeroutput">BZ_MEM_ERROR</code>.</p> +<p>Possible assignments to +<code class="computeroutput">bzerror</code>:</p> +<pre class="programlisting">BZ_CONFIG_ERROR + if the library has been mis-compiled +BZ_PARAM_ERROR + if f is NULL + or small is neither 0 nor 1 + or ( unused == NULL && nUnused != 0 ) + or ( unused != NULL && !(0 <= nUnused <= BZ_MAX_UNUSED) ) +BZ_IO_ERROR + if ferror(f) is nonzero +BZ_MEM_ERROR + if insufficient memory is available +BZ_OK + otherwise.</pre> +<p>Possible return values:</p> +<pre class="programlisting">Pointer to an abstract BZFILE + if bzerror is BZ_OK +NULL + otherwise</pre> +<p>Allowable next actions:</p> +<pre class="programlisting">BZ2_bzRead + if bzerror is BZ_OK +BZ2_bzClose + otherwise</pre> +</div> +<div class="sect2" lang="en"> +<div class="titlepage"><div><div><h3 class="title"> +<a name="bzread"></a>3.4.2. <code class="computeroutput">BZ2_bzRead</code></h3></div></div></div> +<pre class="programlisting">int BZ2_bzRead ( int *bzerror, BZFILE *b, void *buf, int len );</pre> +<p>Reads up to <code class="computeroutput">len</code> +(uncompressed) bytes from the compressed file +<code class="computeroutput">b</code> into the buffer +<code class="computeroutput">buf</code>. If the read was +successful, <code class="computeroutput">bzerror</code> is set to +<code class="computeroutput">BZ_OK</code> and the number of bytes +read is returned. If the logical end-of-stream was detected, +<code class="computeroutput">bzerror</code> will be set to +<code class="computeroutput">BZ_STREAM_END</code>, and the number of +bytes read is returned. All other +<code class="computeroutput">bzerror</code> values denote an +error.</p> +<p><code class="computeroutput">BZ2_bzRead</code> will supply +<code class="computeroutput">len</code> bytes, unless the logical +stream end is detected or an error occurs. Because of this, it +is possible to detect the stream end by observing when the number +of bytes returned is less than the number requested. +Nevertheless, this is regarded as inadvisable; you should instead +check <code class="computeroutput">bzerror</code> after every call +and watch out for +<code class="computeroutput">BZ_STREAM_END</code>.</p> +<p>Internally, <code class="computeroutput">BZ2_bzRead</code> +copies data from the compressed file in chunks of size +<code class="computeroutput">BZ_MAX_UNUSED</code> bytes before +decompressing it. If the file contains more bytes than strictly +needed to reach the logical end-of-stream, +<code class="computeroutput">BZ2_bzRead</code> will almost certainly +read some of the trailing data before signalling +<code class="computeroutput">BZ_SEQUENCE_END</code>. To collect the +read but unused data once +<code class="computeroutput">BZ_SEQUENCE_END</code> has appeared, +call <code class="computeroutput">BZ2_bzReadGetUnused</code> +immediately before +<code class="computeroutput">BZ2_bzReadClose</code>.</p> +<p>Possible assignments to +<code class="computeroutput">bzerror</code>:</p> +<pre class="programlisting">BZ_PARAM_ERROR + if b is NULL or buf is NULL or len < 0 +BZ_SEQUENCE_ERROR + if b was opened with BZ2_bzWriteOpen +BZ_IO_ERROR + if there is an error reading from the compressed file +BZ_UNEXPECTED_EOF + if the compressed file ended before + the logical end-of-stream was detected +BZ_DATA_ERROR + if a data integrity error was detected in the compressed stream +BZ_DATA_ERROR_MAGIC + if the stream does not begin with the requisite header bytes + (ie, is not a bzip2 data file). This is really + a special case of BZ_DATA_ERROR. +BZ_MEM_ERROR + if insufficient memory was available +BZ_STREAM_END + if the logical end of stream was detected. +BZ_OK + otherwise.</pre> +<p>Possible return values:</p> +<pre class="programlisting">number of bytes read + if bzerror is BZ_OK or BZ_STREAM_END +undefined + otherwise</pre> +<p>Allowable next actions:</p> +<pre class="programlisting">collect data from buf, then BZ2_bzRead or BZ2_bzReadClose + if bzerror is BZ_OK +collect data from buf, then BZ2_bzReadClose or BZ2_bzReadGetUnused + if bzerror is BZ_SEQUENCE_END +BZ2_bzReadClose + otherwise</pre> +</div> +<div class="sect2" lang="en"> +<div class="titlepage"><div><div><h3 class="title"> +<a name="bzreadgetunused"></a>3.4.3. <code class="computeroutput">BZ2_bzReadGetUnused</code></h3></div></div></div> +<pre class="programlisting">void BZ2_bzReadGetUnused( int* bzerror, BZFILE *b, + void** unused, int* nUnused );</pre> +<p>Returns data which was read from the compressed file but +was not needed to get to the logical end-of-stream. +<code class="computeroutput">*unused</code> is set to the address of +the data, and <code class="computeroutput">*nUnused</code> to the +number of bytes. <code class="computeroutput">*nUnused</code> will +be set to a value between <code class="computeroutput">0</code> and +<code class="computeroutput">BZ_MAX_UNUSED</code> inclusive.</p> +<p>This function may only be called once +<code class="computeroutput">BZ2_bzRead</code> has signalled +<code class="computeroutput">BZ_STREAM_END</code> but before +<code class="computeroutput">BZ2_bzReadClose</code>.</p> +<p>Possible assignments to +<code class="computeroutput">bzerror</code>:</p> +<pre class="programlisting">BZ_PARAM_ERROR + if b is NULL + or unused is NULL or nUnused is NULL +BZ_SEQUENCE_ERROR + if BZ_STREAM_END has not been signalled + or if b was opened with BZ2_bzWriteOpen +BZ_OK + otherwise</pre> +<p>Allowable next actions:</p> +<pre class="programlisting">BZ2_bzReadClose</pre> +</div> +<div class="sect2" lang="en"> +<div class="titlepage"><div><div><h3 class="title"> +<a name="bzreadclose"></a>3.4.4. <code class="computeroutput">BZ2_bzReadClose</code></h3></div></div></div> +<pre class="programlisting">void BZ2_bzReadClose ( int *bzerror, BZFILE *b );</pre> +<p>Releases all memory pertaining to the compressed file +<code class="computeroutput">b</code>. +<code class="computeroutput">BZ2_bzReadClose</code> does not call +<code class="computeroutput">fclose</code> on the underlying file +handle, so you should do that yourself if appropriate. +<code class="computeroutput">BZ2_bzReadClose</code> should be called +to clean up after all error situations.</p> +<p>Possible assignments to +<code class="computeroutput">bzerror</code>:</p> +<pre class="programlisting">BZ_SEQUENCE_ERROR + if b was opened with BZ2_bzOpenWrite +BZ_OK + otherwise</pre> +<p>Allowable next actions:</p> +<pre class="programlisting">none</pre> +</div> +<div class="sect2" lang="en"> +<div class="titlepage"><div><div><h3 class="title"> +<a name="bzwriteopen"></a>3.4.5. <code class="computeroutput">BZ2_bzWriteOpen</code></h3></div></div></div> +<pre class="programlisting">BZFILE *BZ2_bzWriteOpen( int *bzerror, FILE *f, + int blockSize100k, int verbosity, + int workFactor );</pre> +<p>Prepare to write compressed data to file handle +<code class="computeroutput">f</code>. +<code class="computeroutput">f</code> should refer to a file which +has been opened for writing, and for which the error indicator +(<code class="computeroutput">ferror(f)</code>)is not set.</p> +<p>For the meaning of parameters +<code class="computeroutput">blockSize100k</code>, +<code class="computeroutput">verbosity</code> and +<code class="computeroutput">workFactor</code>, see +<code class="computeroutput">BZ2_bzCompressInit</code>.</p> +<p>All required memory is allocated at this stage, so if the +call completes successfully, +<code class="computeroutput">BZ_MEM_ERROR</code> cannot be signalled +by a subsequent call to +<code class="computeroutput">BZ2_bzWrite</code>.</p> +<p>Possible assignments to +<code class="computeroutput">bzerror</code>:</p> +<pre class="programlisting">BZ_CONFIG_ERROR + if the library has been mis-compiled +BZ_PARAM_ERROR + if f is NULL + or blockSize100k < 1 or blockSize100k > 9 +BZ_IO_ERROR + if ferror(f) is nonzero +BZ_MEM_ERROR + if insufficient memory is available +BZ_OK + otherwise</pre> +<p>Possible return values:</p> +<pre class="programlisting">Pointer to an abstract BZFILE + if bzerror is BZ_OK +NULL + otherwise</pre> +<p>Allowable next actions:</p> +<pre class="programlisting">BZ2_bzWrite + if bzerror is BZ_OK + (you could go directly to BZ2_bzWriteClose, but this would be pretty pointless) +BZ2_bzWriteClose + otherwise</pre> +</div> +<div class="sect2" lang="en"> +<div class="titlepage"><div><div><h3 class="title"> +<a name="bzwrite"></a>3.4.6. <code class="computeroutput">BZ2_bzWrite</code></h3></div></div></div> +<pre class="programlisting">void BZ2_bzWrite ( int *bzerror, BZFILE *b, void *buf, int len );</pre> +<p>Absorbs <code class="computeroutput">len</code> bytes from the +buffer <code class="computeroutput">buf</code>, eventually to be +compressed and written to the file.</p> +<p>Possible assignments to +<code class="computeroutput">bzerror</code>:</p> +<pre class="programlisting">BZ_PARAM_ERROR + if b is NULL or buf is NULL or len < 0 +BZ_SEQUENCE_ERROR + if b was opened with BZ2_bzReadOpen +BZ_IO_ERROR + if there is an error writing the compressed file. +BZ_OK + otherwise</pre> +</div> +<div class="sect2" lang="en"> +<div class="titlepage"><div><div><h3 class="title"> +<a name="bzwriteclose"></a>3.4.7. <code class="computeroutput">BZ2_bzWriteClose</code></h3></div></div></div> +<pre class="programlisting">void BZ2_bzWriteClose( int *bzerror, BZFILE* f, + int abandon, + unsigned int* nbytes_in, + unsigned int* nbytes_out ); + +void BZ2_bzWriteClose64( int *bzerror, BZFILE* f, + int abandon, + unsigned int* nbytes_in_lo32, + unsigned int* nbytes_in_hi32, + unsigned int* nbytes_out_lo32, + unsigned int* nbytes_out_hi32 );</pre> +<p>Compresses and flushes to the compressed file all data so +far supplied by <code class="computeroutput">BZ2_bzWrite</code>. +The logical end-of-stream markers are also written, so subsequent +calls to <code class="computeroutput">BZ2_bzWrite</code> are +illegal. All memory associated with the compressed file +<code class="computeroutput">b</code> is released. +<code class="computeroutput">fflush</code> is called on the +compressed file, but it is not +<code class="computeroutput">fclose</code>'d.</p> +<p>If <code class="computeroutput">BZ2_bzWriteClose</code> is +called to clean up after an error, the only action is to release +the memory. The library records the error codes issued by +previous calls, so this situation will be detected automatically. +There is no attempt to complete the compression operation, nor to +<code class="computeroutput">fflush</code> the compressed file. You +can force this behaviour to happen even in the case of no error, +by passing a nonzero value to +<code class="computeroutput">abandon</code>.</p> +<p>If <code class="computeroutput">nbytes_in</code> is non-null, +<code class="computeroutput">*nbytes_in</code> will be set to be the +total volume of uncompressed data handled. Similarly, +<code class="computeroutput">nbytes_out</code> will be set to the +total volume of compressed data written. For compatibility with +older versions of the library, +<code class="computeroutput">BZ2_bzWriteClose</code> only yields the +lower 32 bits of these counts. Use +<code class="computeroutput">BZ2_bzWriteClose64</code> if you want +the full 64 bit counts. These two functions are otherwise +absolutely identical.</p> +<p>Possible assignments to +<code class="computeroutput">bzerror</code>:</p> +<pre class="programlisting">BZ_SEQUENCE_ERROR + if b was opened with BZ2_bzReadOpen +BZ_IO_ERROR + if there is an error writing the compressed file +BZ_OK + otherwise</pre> +</div> +<div class="sect2" lang="en"> +<div class="titlepage"><div><div><h3 class="title"> +<a name="embed"></a>3.4.8. Handling embedded compressed data streams</h3></div></div></div> +<p>The high-level library facilitates use of +<code class="computeroutput">bzip2</code> data streams which form +some part of a surrounding, larger data stream.</p> +<div class="itemizedlist"><ul type="bullet"> +<li style="list-style-type: disc"><p>For writing, the library takes an open file handle, + writes compressed data to it, + <code class="computeroutput">fflush</code>es it but does not + <code class="computeroutput">fclose</code> it. The calling + application can write its own data before and after the + compressed data stream, using that same file handle.</p></li> +<li style="list-style-type: disc"><p>Reading is more complex, and the facilities are not as + general as they could be since generality is hard to reconcile + with efficiency. <code class="computeroutput">BZ2_bzRead</code> + reads from the compressed file in blocks of size + <code class="computeroutput">BZ_MAX_UNUSED</code> bytes, and in + doing so probably will overshoot the logical end of compressed + stream. To recover this data once decompression has ended, + call <code class="computeroutput">BZ2_bzReadGetUnused</code> after + the last call of <code class="computeroutput">BZ2_bzRead</code> + (the one returning + <code class="computeroutput">BZ_STREAM_END</code>) but before + calling + <code class="computeroutput">BZ2_bzReadClose</code>.</p></li> +</ul></div> +<p>This mechanism makes it easy to decompress multiple +<code class="computeroutput">bzip2</code> streams placed end-to-end. +As the end of one stream, when +<code class="computeroutput">BZ2_bzRead</code> returns +<code class="computeroutput">BZ_STREAM_END</code>, call +<code class="computeroutput">BZ2_bzReadGetUnused</code> to collect +the unused data (copy it into your own buffer somewhere). That +data forms the start of the next compressed stream. To start +uncompressing that next stream, call +<code class="computeroutput">BZ2_bzReadOpen</code> again, feeding in +the unused data via the <code class="computeroutput">unused</code> / +<code class="computeroutput">nUnused</code> parameters. Keep doing +this until <code class="computeroutput">BZ_STREAM_END</code> return +coincides with the physical end of file +(<code class="computeroutput">feof(f)</code>). In this situation +<code class="computeroutput">BZ2_bzReadGetUnused</code> will of +course return no data.</p> +<p>This should give some feel for how the high-level interface +can be used. If you require extra flexibility, you'll have to +bite the bullet and get to grips with the low-level +interface.</p> +</div> +<div class="sect2" lang="en"> +<div class="titlepage"><div><div><h3 class="title"> +<a name="std-rdwr"></a>3.4.9. Standard file-reading/writing code</h3></div></div></div> +<p>Here's how you'd write data to a compressed file:</p> +<pre class="programlisting">FILE* f; +BZFILE* b; +int nBuf; +char buf[ /* whatever size you like */ ]; +int bzerror; +int nWritten; + +f = fopen ( "myfile.bz2", "w" ); +if ( !f ) { + /* handle error */ +} +b = BZ2_bzWriteOpen( &bzerror, f, 9 ); +if (bzerror != BZ_OK) { + BZ2_bzWriteClose ( b ); + /* handle error */ +} + +while ( /* condition */ ) { + /* get data to write into buf, and set nBuf appropriately */ + nWritten = BZ2_bzWrite ( &bzerror, b, buf, nBuf ); + if (bzerror == BZ_IO_ERROR) { + BZ2_bzWriteClose ( &bzerror, b ); + /* handle error */ + } +} + +BZ2_bzWriteClose( &bzerror, b ); +if (bzerror == BZ_IO_ERROR) { + /* handle error */ +}</pre> +<p>And to read from a compressed file:</p> +<pre class="programlisting">FILE* f; +BZFILE* b; +int nBuf; +char buf[ /* whatever size you like */ ]; +int bzerror; +int nWritten; + +f = fopen ( "myfile.bz2", "r" ); +if ( !f ) { + /* handle error */ +} +b = BZ2_bzReadOpen ( &bzerror, f, 0, NULL, 0 ); +if ( bzerror != BZ_OK ) { + BZ2_bzReadClose ( &bzerror, b ); + /* handle error */ +} + +bzerror = BZ_OK; +while ( bzerror == BZ_OK && /* arbitrary other conditions */) { + nBuf = BZ2_bzRead ( &bzerror, b, buf, /* size of buf */ ); + if ( bzerror == BZ_OK ) { + /* do something with buf[0 .. nBuf-1] */ + } +} +if ( bzerror != BZ_STREAM_END ) { + BZ2_bzReadClose ( &bzerror, b ); + /* handle error */ +} else { + BZ2_bzReadClose ( &bzerror, b ); +}</pre> +</div> +</div> +<div class="sect1" lang="en"> +<div class="titlepage"><div><div><h2 class="title" style="clear: both"> +<a name="util-fns"></a>3.5. Utility functions</h2></div></div></div> +<div class="sect2" lang="en"> +<div class="titlepage"><div><div><h3 class="title"> +<a name="bzbufftobuffcompress"></a>3.5.1. <code class="computeroutput">BZ2_bzBuffToBuffCompress</code></h3></div></div></div> +<pre class="programlisting">int BZ2_bzBuffToBuffCompress( char* dest, + unsigned int* destLen, + char* source, + unsigned int sourceLen, + int blockSize100k, + int verbosity, + int workFactor );</pre> +<p>Attempts to compress the data in <code class="computeroutput">source[0 +.. sourceLen-1]</code> into the destination buffer, +<code class="computeroutput">dest[0 .. *destLen-1]</code>. If the +destination buffer is big enough, +<code class="computeroutput">*destLen</code> is set to the size of +the compressed data, and <code class="computeroutput">BZ_OK</code> +is returned. If the compressed data won't fit, +<code class="computeroutput">*destLen</code> is unchanged, and +<code class="computeroutput">BZ_OUTBUFF_FULL</code> is +returned.</p> +<p>Compression in this manner is a one-shot event, done with a +single call to this function. The resulting compressed data is a +complete <code class="computeroutput">bzip2</code> format data +stream. There is no mechanism for making additional calls to +provide extra input data. If you want that kind of mechanism, +use the low-level interface.</p> +<p>For the meaning of parameters +<code class="computeroutput">blockSize100k</code>, +<code class="computeroutput">verbosity</code> and +<code class="computeroutput">workFactor</code>, see +<code class="computeroutput">BZ2_bzCompressInit</code>.</p> +<p>To guarantee that the compressed data will fit in its +buffer, allocate an output buffer of size 1% larger than the +uncompressed data, plus six hundred extra bytes.</p> +<p><code class="computeroutput">BZ2_bzBuffToBuffDecompress</code> +will not write data at or beyond +<code class="computeroutput">dest[*destLen]</code>, even in case of +buffer overflow.</p> +<p>Possible return values:</p> +<pre class="programlisting">BZ_CONFIG_ERROR + if the library has been mis-compiled +BZ_PARAM_ERROR + if dest is NULL or destLen is NULL + or blockSize100k < 1 or blockSize100k > 9 + or verbosity < 0 or verbosity > 4 + or workFactor < 0 or workFactor > 250 +BZ_MEM_ERROR + if insufficient memory is available +BZ_OUTBUFF_FULL + if the size of the compressed data exceeds *destLen +BZ_OK + otherwise</pre> +</div> +<div class="sect2" lang="en"> +<div class="titlepage"><div><div><h3 class="title"> +<a name="bzbufftobuffdecompress"></a>3.5.2. <code class="computeroutput">BZ2_bzBuffToBuffDecompress</code></h3></div></div></div> +<pre class="programlisting">int BZ2_bzBuffToBuffDecompress( char* dest, + unsigned int* destLen, + char* source, + unsigned int sourceLen, + int small, + int verbosity );</pre> +<p>Attempts to decompress the data in <code class="computeroutput">source[0 +.. sourceLen-1]</code> into the destination buffer, +<code class="computeroutput">dest[0 .. *destLen-1]</code>. If the +destination buffer is big enough, +<code class="computeroutput">*destLen</code> is set to the size of +the uncompressed data, and <code class="computeroutput">BZ_OK</code> +is returned. If the compressed data won't fit, +<code class="computeroutput">*destLen</code> is unchanged, and +<code class="computeroutput">BZ_OUTBUFF_FULL</code> is +returned.</p> +<p><code class="computeroutput">source</code> is assumed to hold +a complete <code class="computeroutput">bzip2</code> format data +stream. +<code class="computeroutput">BZ2_bzBuffToBuffDecompress</code> tries +to decompress the entirety of the stream into the output +buffer.</p> +<p>For the meaning of parameters +<code class="computeroutput">small</code> and +<code class="computeroutput">verbosity</code>, see +<code class="computeroutput">BZ2_bzDecompressInit</code>.</p> +<p>Because the compression ratio of the compressed data cannot +be known in advance, there is no easy way to guarantee that the +output buffer will be big enough. You may of course make +arrangements in your code to record the size of the uncompressed +data, but such a mechanism is beyond the scope of this +library.</p> +<p><code class="computeroutput">BZ2_bzBuffToBuffDecompress</code> +will not write data at or beyond +<code class="computeroutput">dest[*destLen]</code>, even in case of +buffer overflow.</p> +<p>Possible return values:</p> +<pre class="programlisting">BZ_CONFIG_ERROR + if the library has been mis-compiled +BZ_PARAM_ERROR + if dest is NULL or destLen is NULL + or small != 0 && small != 1 + or verbosity < 0 or verbosity > 4 +BZ_MEM_ERROR + if insufficient memory is available +BZ_OUTBUFF_FULL + if the size of the compressed data exceeds *destLen +BZ_DATA_ERROR + if a data integrity error was detected in the compressed data +BZ_DATA_ERROR_MAGIC + if the compressed data doesn't begin with the right magic bytes +BZ_UNEXPECTED_EOF + if the compressed data ends unexpectedly +BZ_OK + otherwise</pre> +</div> +</div> +<div class="sect1" lang="en"> +<div class="titlepage"><div><div><h2 class="title" style="clear: both"> +<a name="zlib-compat"></a>3.6. <code class="computeroutput">zlib</code> compatibility functions</h2></div></div></div> +<p>Yoshioka Tsuneo has contributed some functions to give +better <code class="computeroutput">zlib</code> compatibility. +These functions are <code class="computeroutput">BZ2_bzopen</code>, +<code class="computeroutput">BZ2_bzread</code>, +<code class="computeroutput">BZ2_bzwrite</code>, +<code class="computeroutput">BZ2_bzflush</code>, +<code class="computeroutput">BZ2_bzclose</code>, +<code class="computeroutput">BZ2_bzerror</code> and +<code class="computeroutput">BZ2_bzlibVersion</code>. These +functions are not (yet) officially part of the library. If they +break, you get to keep all the pieces. Nevertheless, I think +they work ok.</p> +<pre class="programlisting">typedef void BZFILE; + +const char * BZ2_bzlibVersion ( void );</pre> +<p>Returns a string indicating the library version.</p> +<pre class="programlisting">BZFILE * BZ2_bzopen ( const char *path, const char *mode ); +BZFILE * BZ2_bzdopen ( int fd, const char *mode );</pre> +<p>Opens a <code class="computeroutput">.bz2</code> file for +reading or writing, using either its name or a pre-existing file +descriptor. Analogous to <code class="computeroutput">fopen</code> +and <code class="computeroutput">fdopen</code>.</p> +<pre class="programlisting">int BZ2_bzread ( BZFILE* b, void* buf, int len ); +int BZ2_bzwrite ( BZFILE* b, void* buf, int len );</pre> +<p>Reads/writes data from/to a previously opened +<code class="computeroutput">BZFILE</code>. Analogous to +<code class="computeroutput">fread</code> and +<code class="computeroutput">fwrite</code>.</p> +<pre class="programlisting">int BZ2_bzflush ( BZFILE* b ); +void BZ2_bzclose ( BZFILE* b );</pre> +<p>Flushes/closes a <code class="computeroutput">BZFILE</code>. +<code class="computeroutput">BZ2_bzflush</code> doesn't actually do +anything. Analogous to <code class="computeroutput">fflush</code> +and <code class="computeroutput">fclose</code>.</p> +<pre class="programlisting">const char * BZ2_bzerror ( BZFILE *b, int *errnum )</pre> +<p>Returns a string describing the more recent error status of +<code class="computeroutput">b</code>, and also sets +<code class="computeroutput">*errnum</code> to its numerical +value.</p> +</div> +<div class="sect1" lang="en"> +<div class="titlepage"><div><div><h2 class="title" style="clear: both"> +<a name="stdio-free"></a>3.7. Using the library in a <code class="computeroutput">stdio</code>-free environment</h2></div></div></div> +<div class="sect2" lang="en"> +<div class="titlepage"><div><div><h3 class="title"> +<a name="stdio-bye"></a>3.7.1. Getting rid of <code class="computeroutput">stdio</code></h3></div></div></div> +<p>In a deeply embedded application, you might want to use +just the memory-to-memory functions. You can do this +conveniently by compiling the library with preprocessor symbol +<code class="computeroutput">BZ_NO_STDIO</code> defined. Doing this +gives you a library containing only the following eight +functions:</p> +<p><code class="computeroutput">BZ2_bzCompressInit</code>, +<code class="computeroutput">BZ2_bzCompress</code>, +<code class="computeroutput">BZ2_bzCompressEnd</code> +<code class="computeroutput">BZ2_bzDecompressInit</code>, +<code class="computeroutput">BZ2_bzDecompress</code>, +<code class="computeroutput">BZ2_bzDecompressEnd</code> +<code class="computeroutput">BZ2_bzBuffToBuffCompress</code>, +<code class="computeroutput">BZ2_bzBuffToBuffDecompress</code></p> +<p>When compiled like this, all functions will ignore +<code class="computeroutput">verbosity</code> settings.</p> +</div> +<div class="sect2" lang="en"> +<div class="titlepage"><div><div><h3 class="title"> +<a name="critical-error"></a>3.7.2. Critical error handling</h3></div></div></div> +<p><code class="computeroutput">libbzip2</code> contains a number +of internal assertion checks which should, needless to say, never +be activated. Nevertheless, if an assertion should fail, +behaviour depends on whether or not the library was compiled with +<code class="computeroutput">BZ_NO_STDIO</code> set.</p> +<p>For a normal compile, an assertion failure yields the +message:</p> +<div class="blockquote"><blockquote class="blockquote"> +<p>bzip2/libbzip2: internal error number N.</p> +<p>This is a bug in bzip2/libbzip2, 1.0.5 of 10 December 2007. +Please report it to me at: jseward@bzip.org. If this happened +when you were using some program which uses libbzip2 as a +component, you should also report this bug to the author(s) +of that program. Please make an effort to report this bug; +timely and accurate bug reports eventually lead to higher +quality software. Thanks. Julian Seward, 10 December 2007. +</p> +</blockquote></div> +<p>where <code class="computeroutput">N</code> is some error code +number. If <code class="computeroutput">N == 1007</code>, it also +prints some extra text advising the reader that unreliable memory +is often associated with internal error 1007. (This is a +frequently-observed-phenomenon with versions 1.0.0/1.0.1).</p> +<p><code class="computeroutput">exit(3)</code> is then +called.</p> +<p>For a <code class="computeroutput">stdio</code>-free library, +assertion failures result in a call to a function declared +as:</p> +<pre class="programlisting">extern void bz_internal_error ( int errcode );</pre> +<p>The relevant code is passed as a parameter. You should +supply such a function.</p> +<p>In either case, once an assertion failure has occurred, any +<code class="computeroutput">bz_stream</code> records involved can +be regarded as invalid. You should not attempt to resume normal +operation with them.</p> +<p>You may, of course, change critical error handling to suit +your needs. As I said above, critical errors indicate bugs in +the library and should not occur. All "normal" error situations +are indicated via error return codes from functions, and can be +recovered from.</p> +</div> +</div> +<div class="sect1" lang="en"> +<div class="titlepage"><div><div><h2 class="title" style="clear: both"> +<a name="win-dll"></a>3.8. Making a Windows DLL</h2></div></div></div> +<p>Everything related to Windows has been contributed by +Yoshioka Tsuneo +(<code class="computeroutput">tsuneo@rr.iij4u.or.jp</code>), so +you should send your queries to him (but perhaps Cc: me, +<code class="computeroutput">jseward@bzip.org</code>).</p> +<p>My vague understanding of what to do is: using Visual C++ +5.0, open the project file +<code class="computeroutput">libbz2.dsp</code>, and build. That's +all.</p> +<p>If you can't open the project file for some reason, make a +new one, naming these files: +<code class="computeroutput">blocksort.c</code>, +<code class="computeroutput">bzlib.c</code>, +<code class="computeroutput">compress.c</code>, +<code class="computeroutput">crctable.c</code>, +<code class="computeroutput">decompress.c</code>, +<code class="computeroutput">huffman.c</code>, +<code class="computeroutput">randtable.c</code> and +<code class="computeroutput">libbz2.def</code>. You will also need +to name the header files <code class="computeroutput">bzlib.h</code> +and <code class="computeroutput">bzlib_private.h</code>.</p> +<p>If you don't use VC++, you may need to define the +proprocessor symbol +<code class="computeroutput">_WIN32</code>.</p> +<p>Finally, <code class="computeroutput">dlltest.c</code> is a +sample program using the DLL. It has a project file, +<code class="computeroutput">dlltest.dsp</code>.</p> +<p>If you just want a makefile for Visual C, have a look at +<code class="computeroutput">makefile.msc</code>.</p> +<p>Be aware that if you compile +<code class="computeroutput">bzip2</code> itself on Win32, you must +set <code class="computeroutput">BZ_UNIX</code> to 0 and +<code class="computeroutput">BZ_LCCWIN32</code> to 1, in the file +<code class="computeroutput">bzip2.c</code>, before compiling. +Otherwise the resulting binary won't work correctly.</p> +<p>I haven't tried any of this stuff myself, but it all looks +plausible.</p> +</div> +</div> +<div class="chapter" lang="en"> +<div class="titlepage"><div><div><h2 class="title"> +<a name="misc"></a>4. Miscellanea</h2></div></div></div> +<div class="toc"> +<p><b>Table of Contents</b></p> +<dl> +<dt><span class="sect1"><a href="#limits">4.1. Limitations of the compressed file format</a></span></dt> +<dt><span class="sect1"><a href="#port-issues">4.2. Portability issues</a></span></dt> +<dt><span class="sect1"><a href="#bugs">4.3. Reporting bugs</a></span></dt> +<dt><span class="sect1"><a href="#package">4.4. Did you get the right package?</a></span></dt> +<dt><span class="sect1"><a href="#reading">4.5. Further Reading</a></span></dt> +</dl> +</div> +<p>These are just some random thoughts of mine. Your mileage +may vary.</p> +<div class="sect1" lang="en"> +<div class="titlepage"><div><div><h2 class="title" style="clear: both"> +<a name="limits"></a>4.1. Limitations of the compressed file format</h2></div></div></div> +<p><code class="computeroutput">bzip2-1.0.X</code>, +<code class="computeroutput">0.9.5</code> and +<code class="computeroutput">0.9.0</code> use exactly the same file +format as the original version, +<code class="computeroutput">bzip2-0.1</code>. This decision was +made in the interests of stability. Creating yet another +incompatible compressed file format would create further +confusion and disruption for users.</p> +<p>Nevertheless, this is not a painless decision. Development +work since the release of +<code class="computeroutput">bzip2-0.1</code> in August 1997 has +shown complexities in the file format which slow down +decompression and, in retrospect, are unnecessary. These +are:</p> +<div class="itemizedlist"><ul type="bullet"> +<li style="list-style-type: disc"><p>The run-length encoder, which is the first of the + compression transformations, is entirely irrelevant. The + original purpose was to protect the sorting algorithm from the + very worst case input: a string of repeated symbols. But + algorithm steps Q6a and Q6b in the original Burrows-Wheeler + technical report (SRC-124) show how repeats can be handled + without difficulty in block sorting.</p></li> +<li style="list-style-type: disc"> +<p>The randomisation mechanism doesn't really need to be + there. Udi Manber and Gene Myers published a suffix array + construction algorithm a few years back, which can be employed + to sort any block, no matter how repetitive, in O(N log N) + time. Subsequent work by Kunihiko Sadakane has produced a + derivative O(N (log N)^2) algorithm which usually outperforms + the Manber-Myers algorithm.</p> +<p>I could have changed to Sadakane's algorithm, but I find + it to be slower than <code class="computeroutput">bzip2</code>'s + existing algorithm for most inputs, and the randomisation + mechanism protects adequately against bad cases. I didn't + think it was a good tradeoff to make. Partly this is due to + the fact that I was not flooded with email complaints about + <code class="computeroutput">bzip2-0.1</code>'s performance on + repetitive data, so perhaps it isn't a problem for real + inputs.</p> +<p>Probably the best long-term solution, and the one I have + incorporated into 0.9.5 and above, is to use the existing + sorting algorithm initially, and fall back to a O(N (log N)^2) + algorithm if the standard algorithm gets into + difficulties.</p> +</li> +<li style="list-style-type: disc"><p>The compressed file format was never designed to be + handled by a library, and I have had to jump though some hoops + to produce an efficient implementation of decompression. It's + a bit hairy. Try passing + <code class="computeroutput">decompress.c</code> through the C + preprocessor and you'll see what I mean. Much of this + complexity could have been avoided if the compressed size of + each block of data was recorded in the data stream.</p></li> +<li style="list-style-type: disc"><p>An Adler-32 checksum, rather than a CRC32 checksum, + would be faster to compute.</p></li> +</ul></div> +<p>It would be fair to say that the +<code class="computeroutput">bzip2</code> format was frozen before I +properly and fully understood the performance consequences of +doing so.</p> +<p>Improvements which I was able to incorporate into 0.9.0, +despite using the same file format, are:</p> +<div class="itemizedlist"><ul type="bullet"> +<li style="list-style-type: disc"><p>Single array implementation of the inverse BWT. This + significantly speeds up decompression, presumably because it + reduces the number of cache misses.</p></li> +<li style="list-style-type: disc"><p>Faster inverse MTF transform for large MTF values. + The new implementation is based on the notion of sliding blocks + of values.</p></li> +<li style="list-style-type: disc"><p><code class="computeroutput">bzip2-0.9.0</code> now reads + and writes files with <code class="computeroutput">fread</code> + and <code class="computeroutput">fwrite</code>; version 0.1 used + <code class="computeroutput">putc</code> and + <code class="computeroutput">getc</code>. Duh! Well, you live + and learn.</p></li> +</ul></div> +<p>Further ahead, it would be nice to be able to do random +access into files. This will require some careful design of +compressed file formats.</p> +</div> +<div class="sect1" lang="en"> +<div class="titlepage"><div><div><h2 class="title" style="clear: both"> +<a name="port-issues"></a>4.2. Portability issues</h2></div></div></div> +<p>After some consideration, I have decided not to use GNU +<code class="computeroutput">autoconf</code> to configure 0.9.5 or +1.0.</p> +<p><code class="computeroutput">autoconf</code>, admirable and +wonderful though it is, mainly assists with portability problems +between Unix-like platforms. But +<code class="computeroutput">bzip2</code> doesn't have much in the +way of portability problems on Unix; most of the difficulties +appear when porting to the Mac, or to Microsoft's operating +systems. <code class="computeroutput">autoconf</code> doesn't help +in those cases, and brings in a whole load of new +complexity.</p> +<p>Most people should be able to compile the library and +program under Unix straight out-of-the-box, so to speak, +especially if you have a version of GNU C available.</p> +<p>There are a couple of +<code class="computeroutput">__inline__</code> directives in the +code. GNU C (<code class="computeroutput">gcc</code>) should be +able to handle them. If you're not using GNU C, your C compiler +shouldn't see them at all. If your compiler does, for some +reason, see them and doesn't like them, just +<code class="computeroutput">#define</code> +<code class="computeroutput">__inline__</code> to be +<code class="computeroutput">/* */</code>. One easy way to do this +is to compile with the flag +<code class="computeroutput">-D__inline__=</code>, which should be +understood by most Unix compilers.</p> +<p>If you still have difficulties, try compiling with the +macro <code class="computeroutput">BZ_STRICT_ANSI</code> defined. +This should enable you to build the library in a strictly ANSI +compliant environment. Building the program itself like this is +dangerous and not supported, since you remove +<code class="computeroutput">bzip2</code>'s checks against +compressing directories, symbolic links, devices, and other +not-really-a-file entities. This could cause filesystem +corruption!</p> +<p>One other thing: if you create a +<code class="computeroutput">bzip2</code> binary for public distribution, +please consider linking it statically (<code class="computeroutput">gcc +-static</code>). This avoids all sorts of library-version +issues that others may encounter later on.</p> +<p>If you build <code class="computeroutput">bzip2</code> on +Win32, you must set <code class="computeroutput">BZ_UNIX</code> to 0 +and <code class="computeroutput">BZ_LCCWIN32</code> to 1, in the +file <code class="computeroutput">bzip2.c</code>, before compiling. +Otherwise the resulting binary won't work correctly.</p> +</div> +<div class="sect1" lang="en"> +<div class="titlepage"><div><div><h2 class="title" style="clear: both"> +<a name="bugs"></a>4.3. Reporting bugs</h2></div></div></div> +<p>I tried pretty hard to make sure +<code class="computeroutput">bzip2</code> is bug free, both by +design and by testing. Hopefully you'll never need to read this +section for real.</p> +<p>Nevertheless, if <code class="computeroutput">bzip2</code> dies +with a segmentation fault, a bus error or an internal assertion +failure, it will ask you to email me a bug report. Experience from +years of feedback of bzip2 users indicates that almost all these +problems can be traced to either compiler bugs or hardware +problems.</p> +<div class="itemizedlist"><ul type="bullet"> +<li style="list-style-type: disc"> +<p>Recompile the program with no optimisation, and + see if it works. And/or try a different compiler. I heard all + sorts of stories about various flavours of GNU C (and other + compilers) generating bad code for + <code class="computeroutput">bzip2</code>, and I've run across two + such examples myself.</p> +<p>2.7.X versions of GNU C are known to generate bad code + from time to time, at high optimisation levels. If you get + problems, try using the flags + <code class="computeroutput">-O2</code> + <code class="computeroutput">-fomit-frame-pointer</code> + <code class="computeroutput">-fno-strength-reduce</code>. You + should specifically <span class="emphasis"><em>not</em></span> use + <code class="computeroutput">-funroll-loops</code>.</p> +<p>You may notice that the Makefile runs six tests as part + of the build process. If the program passes all of these, it's + a pretty good (but not 100%) indication that the compiler has + done its job correctly.</p> +</li> +<li style="list-style-type: disc"> +<p>If <code class="computeroutput">bzip2</code> + crashes randomly, and the crashes are not repeatable, you may + have a flaky memory subsystem. + <code class="computeroutput">bzip2</code> really hammers your + memory hierarchy, and if it's a bit marginal, you may get these + problems. Ditto if your disk or I/O subsystem is slowly + failing. Yup, this really does happen.</p> +<p>Try using a different machine of the same type, and see + if you can repeat the problem.</p> +</li> +<li style="list-style-type: disc"><p>This isn't really a bug, but ... If + <code class="computeroutput">bzip2</code> tells you your file is + corrupted on decompression, and you obtained the file via FTP, + there is a possibility that you forgot to tell FTP to do a + binary mode transfer. That absolutely will cause the file to + be non-decompressible. You'll have to transfer it + again.</p></li> +</ul></div> +<p>If you've incorporated +<code class="computeroutput">libbzip2</code> into your own program +and are getting problems, please, please, please, check that the +parameters you are passing in calls to the library, are correct, +and in accordance with what the documentation says is allowable. +I have tried to make the library robust against such problems, +but I'm sure I haven't succeeded.</p> +<p>Finally, if the above comments don't help, you'll have to +send me a bug report. Now, it's just amazing how many people +will send me a bug report saying something like:</p> +<pre class="programlisting">bzip2 crashed with segmentation fault on my machine</pre> +<p>and absolutely nothing else. Needless to say, a such a +report is <span class="emphasis"><em>totally, utterly, completely and +comprehensively 100% useless; a waste of your time, my time, and +net bandwidth</em></span>. With no details at all, there's no way +I can possibly begin to figure out what the problem is.</p> +<p>The rules of the game are: facts, facts, facts. Don't omit +them because "oh, they won't be relevant". At the bare +minimum:</p> +<pre class="programlisting">Machine type. Operating system version. +Exact version of bzip2 (do bzip2 -V). +Exact version of the compiler used. +Flags passed to the compiler.</pre> +<p>However, the most important single thing that will help me +is the file that you were trying to compress or decompress at the +time the problem happened. Without that, my ability to do +anything more than speculate about the cause, is limited.</p> +</div> +<div class="sect1" lang="en"> +<div class="titlepage"><div><div><h2 class="title" style="clear: both"> +<a name="package"></a>4.4. Did you get the right package?</h2></div></div></div> +<p><code class="computeroutput">bzip2</code> is a resource hog. +It soaks up large amounts of CPU cycles and memory. Also, it +gives very large latencies. In the worst case, you can feed many +megabytes of uncompressed data into the library before getting +any compressed output, so this probably rules out applications +requiring interactive behaviour.</p> +<p>These aren't faults of my implementation, I hope, but more +an intrinsic property of the Burrows-Wheeler transform +(unfortunately). Maybe this isn't what you want.</p> +<p>If you want a compressor and/or library which is faster, +uses less memory but gets pretty good compression, and has +minimal latency, consider Jean-loup Gailly's and Mark Adler's +work, <code class="computeroutput">zlib-1.2.1</code> and +<code class="computeroutput">gzip-1.2.4</code>. Look for them at +<a href="http://www.zlib.org" target="_top">http://www.zlib.org</a> and +<a href="http://www.gzip.org" target="_top">http://www.gzip.org</a> +respectively.</p> +<p>For something faster and lighter still, you might try Markus F +X J Oberhumer's <code class="computeroutput">LZO</code> real-time +compression/decompression library, at +<a href="http://www.oberhumer.com/opensource" target="_top">http://www.oberhumer.com/opensource</a>.</p> +</div> +<div class="sect1" lang="en"> +<div class="titlepage"><div><div><h2 class="title" style="clear: both"> +<a name="reading"></a>4.5. Further Reading</h2></div></div></div> +<p><code class="computeroutput">bzip2</code> is not research +work, in the sense that it doesn't present any new ideas. +Rather, it's an engineering exercise based on existing +ideas.</p> +<p>Four documents describe essentially all the ideas behind +<code class="computeroutput">bzip2</code>:</p> +<div class="literallayout"><p>Michael Burrows and D. J. Wheeler:<br> + "A block-sorting lossless data compression algorithm"<br> + 10th May 1994. <br> + Digital SRC Research Report 124.<br> + ftp://ftp.digital.com/pub/DEC/SRC/research-reports/SRC-124.ps.gz<br> + If you have trouble finding it, try searching at the<br> + New Zealand Digital Library, http://www.nzdl.org.<br> +<br> +Daniel S. Hirschberg and Debra A. LeLewer<br> + "Efficient Decoding of Prefix Codes"<br> + Communications of the ACM, April 1990, Vol 33, Number 4.<br> + You might be able to get an electronic copy of this<br> + from the ACM Digital Library.<br> +<br> +David J. Wheeler<br> + Program bred3.c and accompanying document bred3.ps.<br> + This contains the idea behind the multi-table Huffman coding scheme.<br> + ftp://ftp.cl.cam.ac.uk/users/djw3/<br> +<br> +Jon L. Bentley and Robert Sedgewick<br> + "Fast Algorithms for Sorting and Searching Strings"<br> + Available from Sedgewick's web page,<br> + www.cs.princeton.edu/~rs<br> +</p></div> +<p>The following paper gives valuable additional insights into +the algorithm, but is not immediately the basis of any code used +in bzip2.</p> +<div class="literallayout"><p>Peter Fenwick:<br> + Block Sorting Text Compression<br> + Proceedings of the 19th Australasian Computer Science Conference,<br> + Melbourne, Australia. Jan 31 - Feb 2, 1996.<br> + ftp://ftp.cs.auckland.ac.nz/pub/peter-f/ACSC96paper.ps</p></div> +<p>Kunihiko Sadakane's sorting algorithm, mentioned above, is +available from:</p> +<div class="literallayout"><p>http://naomi.is.s.u-tokyo.ac.jp/~sada/papers/Sada98b.ps.gz<br> +</p></div> +<p>The Manber-Myers suffix array construction algorithm is +described in a paper available from:</p> +<div class="literallayout"><p>http://www.cs.arizona.edu/people/gene/PAPERS/suffix.ps<br> +</p></div> +<p>Finally, the following papers document some +investigations I made into the performance of sorting +and decompression algorithms:</p> +<div class="literallayout"><p>Julian Seward<br> + On the Performance of BWT Sorting Algorithms<br> + Proceedings of the IEEE Data Compression Conference 2000<br> + Snowbird, Utah. 28-30 March 2000.<br> +<br> +Julian Seward<br> + Space-time Tradeoffs in the Inverse B-W Transform<br> + Proceedings of the IEEE Data Compression Conference 2001<br> + Snowbird, Utah. 27-29 March 2001.<br> +</p></div> +</div> +</div> +</div></body> +</html> diff --git a/src/misc/bzlib/manual.pdf b/src/misc/bzlib/manual.pdf Binary files differnew file mode 100644 index 00000000..f043e164 --- /dev/null +++ b/src/misc/bzlib/manual.pdf diff --git a/src/misc/bzlib/randtable.c b/src/misc/bzlib/randtable.c new file mode 100644 index 00000000..068b7636 --- /dev/null +++ b/src/misc/bzlib/randtable.c @@ -0,0 +1,84 @@ + +/*-------------------------------------------------------------*/ +/*--- Table for randomising repetitive blocks ---*/ +/*--- randtable.c ---*/ +/*-------------------------------------------------------------*/ + +/* ------------------------------------------------------------------ + This file is part of bzip2/libbzip2, a program and library for + lossless, block-sorting data compression. + + bzip2/libbzip2 version 1.0.5 of 10 December 2007 + Copyright (C) 1996-2007 Julian Seward <jseward@bzip.org> + + Please read the WARNING, DISCLAIMER and PATENTS sections in the + README file. + + This program is released under the terms of the license contained + in the file LICENSE. + ------------------------------------------------------------------ */ + + +#include "bzlib_private.h" + + +/*---------------------------------------------*/ +Int32 BZ2_rNums[512] = { + 619, 720, 127, 481, 931, 816, 813, 233, 566, 247, + 985, 724, 205, 454, 863, 491, 741, 242, 949, 214, + 733, 859, 335, 708, 621, 574, 73, 654, 730, 472, + 419, 436, 278, 496, 867, 210, 399, 680, 480, 51, + 878, 465, 811, 169, 869, 675, 611, 697, 867, 561, + 862, 687, 507, 283, 482, 129, 807, 591, 733, 623, + 150, 238, 59, 379, 684, 877, 625, 169, 643, 105, + 170, 607, 520, 932, 727, 476, 693, 425, 174, 647, + 73, 122, 335, 530, 442, 853, 695, 249, 445, 515, + 909, 545, 703, 919, 874, 474, 882, 500, 594, 612, + 641, 801, 220, 162, 819, 984, 589, 513, 495, 799, + 161, 604, 958, 533, 221, 400, 386, 867, 600, 782, + 382, 596, 414, 171, 516, 375, 682, 485, 911, 276, + 98, 553, 163, 354, 666, 933, 424, 341, 533, 870, + 227, 730, 475, 186, 263, 647, 537, 686, 600, 224, + 469, 68, 770, 919, 190, 373, 294, 822, 808, 206, + 184, 943, 795, 384, 383, 461, 404, 758, 839, 887, + 715, 67, 618, 276, 204, 918, 873, 777, 604, 560, + 951, 160, 578, 722, 79, 804, 96, 409, 713, 940, + 652, 934, 970, 447, 318, 353, 859, 672, 112, 785, + 645, 863, 803, 350, 139, 93, 354, 99, 820, 908, + 609, 772, 154, 274, 580, 184, 79, 626, 630, 742, + 653, 282, 762, 623, 680, 81, 927, 626, 789, 125, + 411, 521, 938, 300, 821, 78, 343, 175, 128, 250, + 170, 774, 972, 275, 999, 639, 495, 78, 352, 126, + 857, 956, 358, 619, 580, 124, 737, 594, 701, 612, + 669, 112, 134, 694, 363, 992, 809, 743, 168, 974, + 944, 375, 748, 52, 600, 747, 642, 182, 862, 81, + 344, 805, 988, 739, 511, 655, 814, 334, 249, 515, + 897, 955, 664, 981, 649, 113, 974, 459, 893, 228, + 433, 837, 553, 268, 926, 240, 102, 654, 459, 51, + 686, 754, 806, 760, 493, 403, 415, 394, 687, 700, + 946, 670, 656, 610, 738, 392, 760, 799, 887, 653, + 978, 321, 576, 617, 626, 502, 894, 679, 243, 440, + 680, 879, 194, 572, 640, 724, 926, 56, 204, 700, + 707, 151, 457, 449, 797, 195, 791, 558, 945, 679, + 297, 59, 87, 824, 713, 663, 412, 693, 342, 606, + 134, 108, 571, 364, 631, 212, 174, 643, 304, 329, + 343, 97, 430, 751, 497, 314, 983, 374, 822, 928, + 140, 206, 73, 263, 980, 736, 876, 478, 430, 305, + 170, 514, 364, 692, 829, 82, 855, 953, 676, 246, + 369, 970, 294, 750, 807, 827, 150, 790, 288, 923, + 804, 378, 215, 828, 592, 281, 565, 555, 710, 82, + 896, 831, 547, 261, 524, 462, 293, 465, 502, 56, + 661, 821, 976, 991, 658, 869, 905, 758, 745, 193, + 768, 550, 608, 933, 378, 286, 215, 979, 792, 961, + 61, 688, 793, 644, 986, 403, 106, 366, 905, 644, + 372, 567, 466, 434, 645, 210, 389, 550, 919, 135, + 780, 773, 635, 389, 707, 100, 626, 958, 165, 504, + 920, 176, 193, 713, 857, 265, 203, 50, 668, 108, + 645, 990, 626, 197, 510, 357, 358, 850, 858, 364, + 936, 638 +}; + + +/*-------------------------------------------------------------*/ +/*--- end randtable.c ---*/ +/*-------------------------------------------------------------*/ |