From 4a9789e58d27ecaba541ba3fcb0565a334dcd54b Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Tue, 1 Jul 2008 08:01:00 -0700 Subject: [PATCH] Version abc80701 --- Makefile | 2 +- abc.dsp | 44 +- src/aig/aig/aigPartReg.c | 4 +- src/aig/dar/darCut.c | 2 +- src/aig/fra/fra.h | 1 + src/aig/fra/fraInd.c | 57 +- src/aig/fra/fraLcr.c | 2 + src/aig/ntl/ntl.h | 11 +- src/aig/ntl/ntlExtract.c | 5 +- src/aig/ntl/ntlFraig.c | 11 +- src/aig/ntl/ntlMan.c | 9 +- src/aig/ntl/ntlReadBlif.c | 135 +- src/aig/ntl/ntlReadBlif_old.c | 1261 ++++++++++++++++ src/aig/ntl/ntlTime.c | 3 +- src/aig/ntl/ntlUtil.c | 13 +- src/aig/ntl/ntlWriteBlif.c | 267 +++- src/base/abci/abc.c | 45 +- src/base/io/ioReadAiger.c | 104 +- src/base/io/ioWriteAiger.c | 262 +++- src/misc/bzlib/CHANGES | 319 ++++ src/misc/bzlib/LICENSE | 42 + src/misc/bzlib/blocksort.c | 1094 ++++++++++++++ src/misc/bzlib/bzip2.txt | 391 +++++ src/misc/bzlib/bzlib.c | 1571 ++++++++++++++++++++ src/misc/bzlib/bzlib.h | 286 ++++ src/misc/bzlib/bzlib_private.h | 509 +++++++ src/misc/bzlib/compress.c | 672 +++++++++ src/misc/bzlib/crctable.c | 104 ++ src/misc/bzlib/decompress.c | 626 ++++++++ src/misc/bzlib/huffman.c | 205 +++ src/misc/bzlib/link.txt | 2 + src/misc/bzlib/manual.html | 2540 ++++++++++++++++++++++++++++++++ src/misc/bzlib/manual.pdf | Bin 0 -> 288134 bytes src/misc/bzlib/randtable.c | 84 ++ 34 files changed, 10624 insertions(+), 59 deletions(-) create mode 100644 src/aig/ntl/ntlReadBlif_old.c create mode 100644 src/misc/bzlib/CHANGES create mode 100644 src/misc/bzlib/LICENSE create mode 100644 src/misc/bzlib/blocksort.c create mode 100644 src/misc/bzlib/bzip2.txt create mode 100644 src/misc/bzlib/bzlib.c create mode 100644 src/misc/bzlib/bzlib.h create mode 100644 src/misc/bzlib/bzlib_private.h create mode 100644 src/misc/bzlib/compress.c create mode 100644 src/misc/bzlib/crctable.c create mode 100644 src/misc/bzlib/decompress.c create mode 100644 src/misc/bzlib/huffman.c create mode 100644 src/misc/bzlib/link.txt create mode 100644 src/misc/bzlib/manual.html create mode 100644 src/misc/bzlib/manual.pdf create mode 100644 src/misc/bzlib/randtable.c diff --git a/Makefile b/Makefile index 1afaae052..bc17f5a46 100644 --- a/Makefile +++ b/Makefile @@ -32,7 +32,7 @@ OPTFLAGS := -g -O -DLIN64 CFLAGS += -Wall -Wno-unused-function $(OPTFLAGS) $(patsubst %, -I%, $(MODULES)) CXXFLAGS += $(CFLAGS) -LIBS := -ldl -rdynamic -lreadline -ltermcap +LIBS := -ldl -rdynamic -lreadline -ltermcap -lbz2 SRC := GARBAGE := core core.* *.stackdump ./tags $(PROG) diff --git a/abc.dsp b/abc.dsp index 6887188d6..78cc76508 100644 --- a/abc.dsp +++ b/abc.dsp @@ -42,7 +42,7 @@ RSC=rc.exe # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c -# ADD CPP /nologo /W3 /GX /O2 /I "src/base/abc" /I "src/base/abci" /I "src/base/cmd" /I "src/base/io" /I "src/base/main" /I "src/base/ver" /I "src/bdd/cudd" /I "src/bdd/dsd" /I "src/bdd/epd" /I "src/bdd/mtr" /I "src/bdd/parse" /I "src/bdd/reo" /I "src/bdd/cas" /I "src/map/fpga" /I "src/map/mapper" /I "src/map/mio" /I "src/map/super" /I "src/map/if" /I "src/map/pcm" /I "src/map/ply" /I "src/misc/extra" /I "src/misc/mvc" /I "src/misc/st" /I "src/misc/util" /I "src/misc/espresso" /I "src/misc/nm" /I "src/misc/vec" /I "src/misc/hash" /I "src/opt/cut" /I "src/opt/dec" /I "src/opt/fxu" /I "src/opt/rwr" /I "src/opt/sim" /I "src/opt/ret" /I "src/opt/res" /I "src/opt/lpk" /I "src/sat/bsat" /I "src/sat/csat" /I "src/sat/msat" /I "src/sat/fraig" /I "src/aig/ivy" /I "src/aig/hop" /I "src/aig/rwt" /I "src/aig/deco" /I "src/aig/mem" /I "src/aig/dar" /I "src/aig/fra" /I "src/aig/cnf" /I "src/aig/csw" /I "src/aig/ioa" /I "src/aig/aig" /I "src/aig/kit" /I "src/aig/bdc" /I "src/aig/bar" /I "src/aig/ntl" /I "src/aig/nwk" /I "src/aig/tim" /I "src/opt/mfs" /I "src/aig/mfx" /I "src/aig/saig" /I "src/aig/bbr" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /D "__STDC__" /D ABC_DLL=DLLEXPORT /FR /YX /FD /c +# ADD CPP /nologo /W3 /GX /O2 /I "src/base/abc" /I "src/base/abci" /I "src/base/cmd" /I "src/base/io" /I "src/base/main" /I "src/base/ver" /I "src/bdd/cudd" /I "src/bdd/dsd" /I "src/bdd/epd" /I "src/bdd/mtr" /I "src/bdd/parse" /I "src/bdd/reo" /I "src/bdd/cas" /I "src/map/fpga" /I "src/map/mapper" /I "src/map/mio" /I "src/map/super" /I "src/map/if" /I "src/map/pcm" /I "src/map/ply" /I "src/misc/extra" /I "src/misc/mvc" /I "src/misc/st" /I "src/misc/util" /I "src/misc/espresso" /I "src/misc/nm" /I "src/misc/vec" /I "src/misc/hash" /I "src/misc/bzlib" /I "src/opt/cut" /I "src/opt/dec" /I "src/opt/fxu" /I "src/opt/rwr" /I "src/opt/sim" /I "src/opt/ret" /I "src/opt/res" /I "src/opt/lpk" /I "src/sat/bsat" /I "src/sat/csat" /I "src/sat/msat" /I "src/sat/fraig" /I "src/aig/ivy" /I "src/aig/hop" /I "src/aig/rwt" /I "src/aig/deco" /I "src/aig/mem" /I "src/aig/dar" /I "src/aig/fra" /I "src/aig/cnf" /I "src/aig/csw" /I "src/aig/ioa" /I "src/aig/aig" /I "src/aig/kit" /I "src/aig/bdc" /I "src/aig/bar" /I "src/aig/ntl" /I "src/aig/nwk" /I "src/aig/tim" /I "src/opt/mfs" /I "src/aig/mfx" /I "src/aig/saig" /I "src/aig/bbr" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /D "__STDC__" /D ABC_DLL=DLLEXPORT /FR /YX /FD /c # ADD BASE RSC /l 0x409 /d "NDEBUG" # ADD RSC /l 0x409 /d "NDEBUG" BSC32=bscmake.exe @@ -66,7 +66,7 @@ LINK32=link.exe # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c -# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I "src/base/abc" /I "src/base/abci" /I "src/base/cmd" /I "src/base/io" /I "src/base/main" /I "src/base/ver" /I "src/bdd/cudd" /I "src/bdd/dsd" /I "src/bdd/epd" /I "src/bdd/mtr" /I "src/bdd/parse" /I "src/bdd/reo" /I "src/bdd/cas" /I "src/map/fpga" /I "src/map/mapper" /I "src/map/mio" /I "src/map/super" /I "src/map/if" /I "src/map/pcm" /I "src/map/ply" /I "src/misc/extra" /I "src/misc/mvc" /I "src/misc/st" /I "src/misc/util" /I "src/misc/espresso" /I "src/misc/nm" /I "src/misc/vec" /I "src/misc/hash" /I "src/opt/cut" /I "src/opt/dec" /I "src/opt/fxu" /I "src/opt/rwr" /I "src/opt/sim" /I "src/opt/ret" /I "src/opt/res" /I "src/opt/lpk" /I "src/sat/bsat" /I "src/sat/csat" /I "src/sat/msat" /I "src/sat/fraig" /I "src/aig/ivy" /I "src/aig/hop" /I "src/aig/rwt" /I "src/aig/deco" /I "src/aig/mem" /I "src/aig/dar" /I "src/aig/fra" /I "src/aig/cnf" /I "src/aig/csw" /I "src/aig/ioa" /I "src/aig/aig" /I "src/aig/kit" /I "src/aig/bdc" /I "src/aig/bar" /I "src/aig/ntl" /I "src/aig/nwk" /I "src/aig/tim" /I "src/opt/mfs" /I "src/aig/mfx" /I "src/aig/saig" /I "src/aig/bbr" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "__STDC__" /D ABC_DLL=DLLEXPORT /FR /YX /FD /GZ /c +# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I "src/base/abc" /I "src/base/abci" /I "src/base/cmd" /I "src/base/io" /I "src/base/main" /I "src/base/ver" /I "src/bdd/cudd" /I "src/bdd/dsd" /I "src/bdd/epd" /I "src/bdd/mtr" /I "src/bdd/parse" /I "src/bdd/reo" /I "src/bdd/cas" /I "src/map/fpga" /I "src/map/mapper" /I "src/map/mio" /I "src/map/super" /I "src/map/if" /I "src/map/pcm" /I "src/map/ply" /I "src/misc/extra" /I "src/misc/mvc" /I "src/misc/st" /I "src/misc/util" /I "src/misc/espresso" /I "src/misc/nm" /I "src/misc/vec" /I "src/misc/hash" /I "src/misc/bzlib" /I "src/opt/cut" /I "src/opt/dec" /I "src/opt/fxu" /I "src/opt/rwr" /I "src/opt/sim" /I "src/opt/ret" /I "src/opt/res" /I "src/opt/lpk" /I "src/sat/bsat" /I "src/sat/csat" /I "src/sat/msat" /I "src/sat/fraig" /I "src/aig/ivy" /I "src/aig/hop" /I "src/aig/rwt" /I "src/aig/deco" /I "src/aig/mem" /I "src/aig/dar" /I "src/aig/fra" /I "src/aig/cnf" /I "src/aig/csw" /I "src/aig/ioa" /I "src/aig/aig" /I "src/aig/kit" /I "src/aig/bdc" /I "src/aig/bar" /I "src/aig/ntl" /I "src/aig/nwk" /I "src/aig/tim" /I "src/opt/mfs" /I "src/aig/mfx" /I "src/aig/saig" /I "src/aig/bbr" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "__STDC__" /D ABC_DLL=DLLEXPORT /FR /YX /FD /GZ /c # SUBTRACT CPP /X # ADD BASE RSC /l 0x409 /d "_DEBUG" # ADD RSC /l 0x409 /d "_DEBUG" @@ -2449,6 +2449,46 @@ SOURCE=.\src\misc\hash\hashInt.h SOURCE=.\src\misc\hash\hashPtr.h # End Source File # End Group +# Begin Group "bzlib" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\src\misc\bzlib\blocksort.c +# End Source File +# Begin Source File + +SOURCE=.\src\misc\bzlib\bzlib.c +# End Source File +# Begin Source File + +SOURCE=.\src\misc\bzlib\bzlib.h +# End Source File +# Begin Source File + +SOURCE=.\src\misc\bzlib\bzlib_private.h +# End Source File +# Begin Source File + +SOURCE=.\src\misc\bzlib\compress.c +# End Source File +# Begin Source File + +SOURCE=.\src\misc\bzlib\crctable.c +# End Source File +# Begin Source File + +SOURCE=.\src\misc\bzlib\decompress.c +# End Source File +# Begin Source File + +SOURCE=.\src\misc\bzlib\huffman.c +# End Source File +# Begin Source File + +SOURCE=.\src\misc\bzlib\randtable.c +# End Source File +# End Group # End Group # Begin Group "ai" diff --git a/src/aig/aig/aigPartReg.c b/src/aig/aig/aigPartReg.c index 145d20299..96ad18121 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 79e4dcc45..6ebfec9d2 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 025ce0464..e9e7ad9cb 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 9c52d0e22..89c4c6773 100644 --- a/src/aig/fra/fraInd.c +++ b/src/aig/fra/fraInd.c @@ -233,6 +233,43 @@ void Fra_FramesAddMore( Aig_Man_t * p, int nFrames ) free( pLatches ); } +/**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.] @@ -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 c957a7518..92e0d94b1 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 44a9f97c3..e1d3edd1d 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 d6cbfab08..8049ffb83 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 6dce36453..6449cc334 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 cee0bf6cf..06a1a51c8 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 ebfb2a80e..cc019732f 100644 --- a/src/aig/ntl/ntlReadBlif.c +++ b/src/aig/ntl/ntlReadBlif.c @@ -19,6 +19,7 @@ ***********************************************************************/ #include "ntl.h" +#include //////////////////////////////////////////////////////////////////////// /// 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; } @@ -435,6 +452,91 @@ static char * Ioa_ReadLoadFile( char * pFileName ) return pContents; } +/**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.] @@ -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 000000000..ebfb2a80e --- /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 53603cee9..ee3e489b9 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 1fb9f1c62..4fd1762c7 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 f93e3fa13..8c97d3d01 100644 --- a/src/aig/ntl/ntlWriteBlif.c +++ b/src/aig/ntl/ntlWriteBlif.c @@ -21,6 +21,13 @@ #include "ntl.h" #include "ioa.h" +#include +#include + +#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 db8d73278..d3372c9a5 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 3739205d8..9ecc00fd8 100644 --- a/src/base/io/ioReadAiger.c +++ b/src/base/io/ioReadAiger.c @@ -20,6 +20,7 @@ ***********************************************************************/ #include "ioAbc.h" +#include //////////////////////////////////////////////////////////////////////// /// 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 fb107e772..9e5ee8b48 100644 --- a/src/base/io/ioWriteAiger.c +++ b/src/base/io/ioWriteAiger.c @@ -21,6 +21,13 @@ #include "ioAbc.h" +#include +#include + +#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 000000000..6e4f65e2e --- /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 + + 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 000000000..f420cffb6 --- /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 000000000..95adb5ef3 --- /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 + + 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 000000000..4fb9c7435 --- /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 000000000..9d040682d --- /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 + + 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 +# include +# 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 000000000..798f248c8 --- /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 + + 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 +#endif + +#ifdef _WIN32 +# include +# 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 000000000..23427879b --- /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 + + 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 + +#ifndef BZ_NO_STDIO +#include +#include +#include +#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 000000000..7d9b3da75 --- /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 + + 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 000000000..215687b2c --- /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 + + 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 000000000..bba5e0fa3 --- /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 + + 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 000000000..87e79e38a --- /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 + + 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 000000000..cdfca2df4 --- /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 000000000..68259b278 --- /dev/null +++ b/src/misc/bzlib/manual.html @@ -0,0 +1,2540 @@ + + + +bzip2 and libbzip2, version 1.0.5 + + + +
+
+
+

+bzip2 and libbzip2, version 1.0.5

+

A program and library for data compression

+
+

+Julian Seward +

+
http://www.bzip.org
+
+

Version 1.0.5 of 10 December 2007

+
+
+

This program, bzip2, the + associated library libbzip2, and + all documentation, are copyright © 1996-2007 Julian 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:

+
    +
  • Redistributions of source code must retain the + above copyright notice, this list of conditions and the + following disclaimer.

  • +
  • 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.

  • +
  • Altered source versions must be plainly marked + as such, and must not be misrepresented as being the original + software.

  • +
  • 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.

+

PATENTS: To the best of my knowledge, + bzip2 and + libbzip2 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. +

+
+
+
+
+ +
+

+1. Introduction

+

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 statistical compressors.

+

bzip2 is built on top of +libbzip2, a flexible library for +handling compressed data in the +bzip2 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.

+
    +
  • How to use bzip2 describes how to use + bzip2; this is the only part + you need to read if you just want to know how to operate the + program.

  • +
  • Programming with libbzip2 describes the + programming interfaces in detail, and

  • +
  • Miscellanea records some + miscellaneous notes which I thought ought to be recorded + somewhere.

  • +
+
+
+

+2. How to use bzip2

+ +

This chapter contains a copy of the +bzip2 man page, and nothing +else.

+
+

+2.1. NAME

+
    +
  • bzip2, + bunzip2 - a block-sorting file + compressor, v1.0.4

  • +
  • bzcat - + decompresses files to stdout

  • +
  • bzip2recover - + recovers data from damaged bzip2 files

  • +
+
+
+

+2.2. SYNOPSIS

+
    +
  • bzip2 [ + -cdfkqstvzVL123456789 ] [ filenames ... ]

  • +
  • bunzip2 [ + -fkvsVL ] [ filenames ... ]

  • +
  • bzcat [ -s ] [ + filenames ... ]

  • +
  • bzip2recover + filename

  • +
+
+
+

+2.3. 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 statistical 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 command-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, 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.

+

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 +decompression from standard input to standard output.

+

bunzip2 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 +(-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 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 +bzip2 version 0.9.0 or later. +Earlier versions of bzip2 will +stop after decompressing 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 corruption 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, etc.), 2 +to indicate a corrupt compressed file, 3 for an internal +consistency error (eg, bug) which caused +bzip2 to panic.

+
+
+

+2.4. 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 invokation 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 verbosity + 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 significantly 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 handle + 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 versions, which was sometimes + useful. 0.9.5 and above have an improved algorithm which + renders these flags irrelevant.

+
+
+
+

+2.5. 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) +respectively. 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. Decompression 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 +constraints allow, since that maximises the compression achieved. +Compression and decompression speed are virtually 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 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.

+
        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
+
+
+

+2.6. RECOVERING DATA FROM DAMAGED FILES

+

bzip2 compresses files in +blocks, usually 900kbytes long. Each block is handled +independently. If a media or transmission 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 damaged file, and writes a +number of files rec0001file.bz2, +rec0002file.bz2, etc, containing +the extracted blocks. The output filenames are designed so that +the use of wildcards in subsequent processing -- for example, +bzip2 -dc rec*file.bz2 > +recovered_data -- lists 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 minimise any potential data +loss through media or transmission errors, you might consider +compressing with a smaller block size.

+
+
+

+2.7. 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 monitor 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 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 +bzip2 will perform best on +machines with very large caches.

+
+
+

+2.8. 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.5 of +bzip2. 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.

+

bzip2recover 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 +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.

+
+
+

+2.9. AUTHOR

+

Julian Seward, +jseward@bzip.org

+

The ideas embodied in +bzip2 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 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 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.

+
+
+
+

+3.  +Programming with libbzip2 +

+ +

This chapter describes the programming interface to +libbzip2.

+

For general background information, particularly about +memory use and performance aspects, you'd be well advised to read +How to use bzip2 as well.

+
+

+3.1. Top-level structure

+

libbzip2 is a flexible +library for compressing and decompressing data in the +bzip2 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.

+

The structure of +libbzip2's interfaces is similar +to that of Jean-loup Gailly's and Mark Adler's excellent +zlib library.

+

All externally visible symbols have names beginning +BZ2_. This is new in version +1.0. The intention is to minimise pollution of the namespaces of +library clients.

+

To use any part of the library, you need to +#include <bzlib.h> +into your sources.

+
+

+3.1.1. Low-level summary

+

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 +stdio.h, which may be helpful +for embedded applications.

+

The low-level part of the library has no global variables +and is therefore thread-safe.

+

Six routines make up the low level interface: +BZ2_bzCompressInit, +BZ2_bzCompress, and +BZ2_bzCompressEnd for +compression, and a corresponding trio +BZ2_bzDecompressInit, +BZ2_bzDecompress and +BZ2_bzDecompressEnd for +decompression. The *Init +functions allocate memory for compression/decompression and do +other initialisations, whilst the +*End functions close down +operations and release memory.

+

The real work is done by +BZ2_bzCompress and +BZ2_bzDecompress. 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.

+
+
+

+3.1.2. High-level summary

+

This interface provides some handy wrappers around the +low-level interface to facilitate reading and writing +bzip2 format files +(.bz2 files). The routines +provide hooks to facilitate reading files in which the +bzip2 data stream is embedded +within some larger-scale file structure, or where there are +multiple bzip2 data streams +concatenated end-to-end.

+

For reading files, +BZ2_bzReadOpen, +BZ2_bzRead, +BZ2_bzReadClose and +BZ2_bzReadGetUnused are +supplied. For writing files, +BZ2_bzWriteOpen, +BZ2_bzWrite and +BZ2_bzWriteFinish are +available.

+

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 errno to +determine the cause of the error. In that case, you'd need a C +library which correctly supports +errno in a multithreaded +environment.

+

To make the library a little simpler and more portable, +BZ2_bzReadOpen and +BZ2_bzWriteOpen require you to +pass them file handles (FILE*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.

+
+
+

+3.1.3. Utility functions summary

+

For very simple needs, +BZ2_bzBuffToBuffCompress and +BZ2_bzBuffToBuffDecompress 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.

+

Yoshioka Tsuneo +(tsuneo@rr.iij4u.or.jp) has +contributed some functions to give better +zlib compatibility. These +functions are BZ2_bzopen, +BZ2_bzread, +BZ2_bzwrite, +BZ2_bzflush, +BZ2_bzclose, +BZ2_bzerror and +BZ2_bzlibVersion. 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.

+

Yoshioka also contributed modifications to allow the +library to be built as a Windows DLL.

+
+
+
+

+3.2. Error handling

+

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.

+

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.

+

The file bzlib.h contains +all definitions needed to use the library. In particular, you +should definitely not include +bzlib_private.h.

+

In bzlib.h, 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.

+
+
BZ_OK
+

The requested action was completed + successfully.

+
BZ_RUN_OK, BZ_FLUSH_OK, + BZ_FINISH_OK
+

In + BZ2_bzCompress, the requested + flush/finish/nothing-special action was completed + successfully.

+
BZ_STREAM_END
+

Compression of data was completed, or the + logical stream end was detected during + decompression.

+
+

The following return values indicate an error of some +kind.

+
+
BZ_CONFIG_ERROR
+

Indicates that the library has been improperly + compiled on your platform -- a major configuration error. + Specifically, it means that + sizeof(char), + sizeof(short) and + sizeof(int) 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 + sizeof(long) and + sizeof(void*) are 8. Under + LP64, sizeof(int) is still 4, + so libbzip2, which doesn't + use the long type, is + OK.

+
BZ_SEQUENCE_ERROR
+

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. + libbzip2 checks as much as it + can to ensure this is happening, and returns + BZ_SEQUENCE_ERROR 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.

+
BZ_PARAM_ERROR
+

Returned when a parameter to a function call is + out of range or otherwise manifestly incorrect. As with + BZ_SEQUENCE_ERROR, this + denotes a bug in the client code. The distinction between + BZ_PARAM_ERROR and + BZ_SEQUENCE_ERROR is a bit + hazy, but still worth making.

+
BZ_MEM_ERROR
+

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 + BZ2_bzDecompress and + BZ2_bzRead may return + BZ_MEM_ERROR even though some + of the compressed data has been read. The same is not true + for compression; once + BZ2_bzCompressInit or + BZ2_bzWriteOpen have + successfully completed, + BZ_MEM_ERROR cannot + occur.

+
BZ_DATA_ERROR
+

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.

+
BZ_DATA_ERROR_MAGIC
+

As a special case of + BZ_DATA_ERROR, it is + sometimes useful to know when the compressed stream does not + start with the correct magic bytes ('B' 'Z' + 'h').

+
BZ_IO_ERROR
+

Returned by + BZ2_bzRead and + BZ2_bzWrite when there is an + error reading or writing in the compressed file, and by + BZ2_bzReadOpen and + BZ2_bzWriteOpen for attempts + to use a file for which the error indicator (viz, + ferror(f)) is set. On + receipt of BZ_IO_ERROR, the + caller should consult errno + and/or perror to acquire + operating-system specific information about the + problem.

+
BZ_UNEXPECTED_EOF
+

Returned by + BZ2_bzRead when the + compressed file finishes before the logical end of stream is + detected.

+
BZ_OUTBUFF_FULL
+

Returned by + BZ2_bzBuffToBuffCompress and + BZ2_bzBuffToBuffDecompress to + indicate that the output data will not fit into the output + buffer provided.

+
+
+
+

+3.3. Low-level interface

+
+

+3.3.1. BZ2_bzCompressInit

+
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 );
+

Prepares for compression. The +bz_stream structure holds all +data pertaining to the compression activity. A +bz_stream structure should be +allocated and initialised prior to the call. The fields of +bz_stream comprise the entirety +of the user-visible data. state +is a pointer to the private data structures required for +compression.

+

Custom memory allocators are supported, via fields +bzalloc, +bzfree, and +opaque. The value +opaque is passed to as the first +argument to all calls to bzalloc +and bzfree, but is otherwise +ignored by the library. The call bzalloc ( +opaque, n, m ) is expected to return a pointer +p to n * +m bytes of memory, and bzfree ( +opaque, p ) should free that memory.

+

If you don't want to use a custom memory allocator, set +bzalloc, +bzfree and +opaque to +NULL, and the library will then +use the standard malloc / +free routines.

+

Before calling +BZ2_bzCompressInit, fields +bzalloc, +bzfree and +opaque should be filled +appropriately, as just described. Upon return, the internal +state will have been allocated and initialised, and +total_in_lo32, +total_in_hi32, +total_out_lo32 and +total_out_hi32 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 _hi32 +fields to store the upper 32 bits of the count. So, for example, +the total amount of data in is (total_in_hi32 +<< 32) + total_in_lo32.

+

Parameter blockSize100k +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.

+

Parameter verbosity 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 +-DBZ_NO_STDIO, no such output +will appear for any verbosity setting.

+

Parameter workFactor +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.

+

Lower values of workFactor +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.

+

Allowable values range from 0 to 250 inclusive. 0 is a +special case, equivalent to using the default value of 30.

+

Note that the compressed output generated is the same +regardless of whether or not the fallback algorithm is +used.

+

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.

+

Possible return values:

+
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
+

Allowable next actions:

+
BZ2_bzCompress
+  if BZ_OK is returned
+  no specific action needed in case of error
+
+
+

+3.3.2. BZ2_bzCompress

+
int BZ2_bzCompress ( bz_stream *strm, int action );
+

Provides more input and/or output buffer space for the +library. The caller maintains input and output buffers, and +calls BZ2_bzCompress to transfer +data between them.

+

Before each call to +BZ2_bzCompress, +next_in should point at the data +to be compressed, and avail_in +should indicate how many bytes the library may read. +BZ2_bzCompress updates +next_in, +avail_in and +total_in to reflect the number +of bytes it has read.

+

Similarly, next_out should +point to a buffer in which the compressed data is to be placed, +with avail_out indicating how +much output space is available. +BZ2_bzCompress updates +next_out, +avail_out and +total_out to reflect the number +of bytes output.

+

You may provide and remove as little or as much data as you +like on each call of +BZ2_bzCompress. 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.

+

A second purpose of +BZ2_bzCompress is to request a +change of mode of the compressed stream.

+

Conceptually, a compressed stream can be in one of four +states: IDLE, RUNNING, FLUSHING and FINISHING. Before +initialisation +(BZ2_bzCompressInit) and after +termination (BZ2_bzCompressEnd), +a stream is regarded as IDLE.

+

Upon initialisation +(BZ2_bzCompressInit), the stream +is placed in the RUNNING state. Subsequent calls to +BZ2_bzCompress should pass +BZ_RUN as the requested action; +other actions are illegal and will result in +BZ_SEQUENCE_ERROR.

+

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, +BZ2_bzCompress will no longer +attempt to read data from +next_in, but it will want to +write data to next_out. 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 +BZ2_bzCompress.

+

Instead, the calling program passes +BZ_FINISH as an action to +BZ2_bzCompress. This changes +the stream's state to FINISHING. Any remaining input (ie, +next_in[0 .. avail_in-1]) is +compressed and transferred to the output buffer. To do this, +BZ2_bzCompress must be called +repeatedly until all the output has been consumed. At that +point, BZ2_bzCompress returns +BZ_STREAM_END, and the stream's +state is set back to IDLE. +BZ2_bzCompressEnd should then be +called.

+

Just to make sure the calling program does not cheat, the +library makes a note of avail_in +at the time of the first call to +BZ2_bzCompress which has +BZ_FINISH 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 +avail_in over subsequent calls +to BZ2_bzCompress, the library +can detect any attempts to slip in more data to compress. Any +calls for which this is detected will return +BZ_SEQUENCE_ERROR. This +indicates a programming mistake which should be corrected.

+

Instead of asking to finish, the calling program may ask +BZ2_bzCompress 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 BZ2_bzCompress +with an action of BZ_FLUSH, +remove output data, and persist with the +BZ_FLUSH action until the value +BZ_RUN is returned. As with +finishing, BZ2_bzCompress +detects any attempt to provide more input data once the flush has +begun.

+

Once the flush is complete, the stream returns to the +normal RUNNING state.

+

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 +BZ2_bzCompress.

+
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
+

That still looks complicated? Well, fair enough. The +usual sequence of calls for compressing a load of data is:

+
    +
  1. Get started with + BZ2_bzCompressInit.

  2. +
  3. Shovel data in and shlurp out its compressed form + using zero or more calls of + BZ2_bzCompress with action = + BZ_RUN.

  4. +
  5. Finish up. Repeatedly call + BZ2_bzCompress with action = + BZ_FINISH, copying out the + compressed output, until + BZ_STREAM_END is + returned.

  6. +
  7. Close up and go home. Call + BZ2_bzCompressEnd.

  8. +
+

If the data you want to compress fits into your input +buffer all at once, you can skip the calls of +BZ2_bzCompress ( ..., BZ_RUN ) +and just do the BZ2_bzCompress ( ..., BZ_FINISH +) calls.

+

All required memory is allocated by +BZ2_bzCompressInit. The +compression library can accept any data at all (obviously). So +you shouldn't get any error return values from the +BZ2_bzCompress calls. If you +do, they will be +BZ_SEQUENCE_ERROR, and indicate +a bug in your programming.

+

Trivial other possible return values:

+
BZ_PARAM_ERROR
+  if strm is NULL, or strm->s is NULL
+
+
+

+3.3.3. BZ2_bzCompressEnd

+
int BZ2_bzCompressEnd ( bz_stream *strm );
+

Releases all memory associated with a compression +stream.

+

Possible return values:

+
BZ_PARAM_ERROR  if strm is NULL or strm->s is NULL
+BZ_OK           otherwise
+
+
+

+3.3.4. BZ2_bzDecompressInit

+
int BZ2_bzDecompressInit ( bz_stream *strm, int verbosity, int small );
+

Prepares for decompression. As with +BZ2_bzCompressInit, a +bz_stream record should be +allocated and initialised before the call. Fields +bzalloc, +bzfree and +opaque should be set if a custom +memory allocator is required, or made +NULL for the normal +malloc / +free routines. Upon return, the +internal state will have been initialised, and +total_in and +total_out will be zero.

+

For the meaning of parameter +verbosity, see +BZ2_bzCompressInit.

+

If small 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 How to use bzip2 +for more information on memory management.

+

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 +BZ2_bzDecompressInit succeeds, a +subsequent BZ2_bzDecompress +could fail with +BZ_MEM_ERROR.

+

Possible return values:

+
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
+

Allowable next actions:

+
BZ2_bzDecompress
+  if BZ_OK was returned
+  no specific action required in case of error
+
+
+

+3.3.5. BZ2_bzDecompress

+
int BZ2_bzDecompress ( bz_stream *strm );
+

Provides more input and/out output buffer space for the +library. The caller maintains input and output buffers, and uses +BZ2_bzDecompress to transfer +data between them.

+

Before each call to +BZ2_bzDecompress, +next_in should point at the +compressed data, and avail_in +should indicate how many bytes the library may read. +BZ2_bzDecompress updates +next_in, +avail_in and +total_in to reflect the number +of bytes it has read.

+

Similarly, next_out should +point to a buffer in which the uncompressed output is to be +placed, with avail_out +indicating how much output space is available. +BZ2_bzCompress updates +next_out, +avail_out and +total_out to reflect the number +of bytes output.

+

You may provide and remove as little or as much data as you +like on each call of +BZ2_bzDecompress. 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.

+

Use of BZ2_bzDecompress is +simpler than +BZ2_bzCompress.

+

You should provide input and remove output as described +above, and repeatedly call +BZ2_bzDecompress until +BZ_STREAM_END is returned. +Appearance of BZ_STREAM_END +denotes that BZ2_bzDecompress +has detected the logical end of the compressed stream. +BZ2_bzDecompress will not +produce BZ_STREAM_END until all +output data has been placed into the output buffer, so once +BZ_STREAM_END appears, you are +guaranteed to have available all the decompressed output, and +BZ2_bzDecompressEnd can safely +be called.

+

If case of an error return value, you should call +BZ2_bzDecompressEnd to clean up +and release memory.

+

Possible return values:

+
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
+

Allowable next actions:

+
BZ2_bzDecompress
+  if BZ_OK was returned
+BZ2_bzDecompressEnd
+  otherwise
+
+
+

+3.3.6. BZ2_bzDecompressEnd

+
int BZ2_bzDecompressEnd ( bz_stream *strm );
+

Releases all memory associated with a decompression +stream.

+

Possible return values:

+
BZ_PARAM_ERROR
+  if strm is NULL or strm->s is NULL
+BZ_OK
+  otherwise
+

Allowable next actions:

+
  None.
+
+
+
+

+3.4. High-level interface

+

This interface provides functions for reading and writing +bzip2 format files. First, some +general points.

+
    +
  • All of the functions take an + int* first argument, + bzerror. After each call, + bzerror should be consulted + first to determine the outcome of the call. If + bzerror is + BZ_OK, the call completed + successfully, and only then should the return value of the + function (if any) be consulted. If + bzerror is + BZ_IO_ERROR, there was an + error reading/writing the underlying compressed file, and you + should then consult errno / + perror to determine the cause + of the difficulty. bzerror + may also be set to various other values; precise details are + given on a per-function basis below.

  • +
  • If bzerror indicates + an error (ie, anything except + BZ_OK and + BZ_STREAM_END), you should + immediately call + BZ2_bzReadClose (or + BZ2_bzWriteClose, 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 + BZ2_bzReadClose + (BZ2_bzWriteClose) is + undefined. The implication is that (1) + bzerror should be checked + after each call, and (2) if + bzerror indicates an error, + BZ2_bzReadClose + (BZ2_bzWriteClose) should then + be called to clean up.

  • +
  • The FILE* arguments + passed to BZ2_bzReadOpen / + BZ2_bzWriteOpen 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.

  • +
  • Memory allocation requests are handled by + malloc / + free. At present there is no + facility for user-defined memory allocators in the file I/O + functions (could easily be added, though).

  • +
+
+

+3.4.1. BZ2_bzReadOpen

+
typedef void BZFILE;
+
+BZFILE *BZ2_bzReadOpen( int *bzerror, FILE *f, 
+                        int verbosity, int small,
+                        void *unused, int nUnused );
+

Prepare to read compressed data from file handle +f. +f should refer to a file which +has been opened for reading, and for which the error indicator +(ferror(f))is not set. If +small is 1, the library will try +to decompress using less memory, at the expense of speed.

+

For reasons explained below, +BZ2_bzRead will decompress the +nUnused bytes starting at +unused, before starting to read +from the file f. At most +BZ_MAX_UNUSED bytes may be +supplied like this. If this facility is not required, you should +pass NULL and +0 for +unused and +nUnused respectively.

+

For the meaning of parameters +small and +verbosity, see +BZ2_bzDecompressInit.

+

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 BZ2_bzReadOpen +returns BZ_OK but a subsequent +call of BZ2_bzRead will return +BZ_MEM_ERROR.

+

Possible assignments to +bzerror:

+
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.
+

Possible return values:

+
Pointer to an abstract BZFILE
+  if bzerror is BZ_OK
+NULL
+  otherwise
+

Allowable next actions:

+
BZ2_bzRead
+  if bzerror is BZ_OK
+BZ2_bzClose
+  otherwise
+
+
+

+3.4.2. BZ2_bzRead

+
int BZ2_bzRead ( int *bzerror, BZFILE *b, void *buf, int len );
+

Reads up to len +(uncompressed) bytes from the compressed file +b into the buffer +buf. If the read was +successful, bzerror is set to +BZ_OK and the number of bytes +read is returned. If the logical end-of-stream was detected, +bzerror will be set to +BZ_STREAM_END, and the number of +bytes read is returned. All other +bzerror values denote an +error.

+

BZ2_bzRead will supply +len 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 bzerror after every call +and watch out for +BZ_STREAM_END.

+

Internally, BZ2_bzRead +copies data from the compressed file in chunks of size +BZ_MAX_UNUSED bytes before +decompressing it. If the file contains more bytes than strictly +needed to reach the logical end-of-stream, +BZ2_bzRead will almost certainly +read some of the trailing data before signalling +BZ_SEQUENCE_END. To collect the +read but unused data once +BZ_SEQUENCE_END has appeared, +call BZ2_bzReadGetUnused +immediately before +BZ2_bzReadClose.

+

Possible assignments to +bzerror:

+
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.
+

Possible return values:

+
number of bytes read
+  if bzerror is BZ_OK or BZ_STREAM_END
+undefined
+  otherwise
+

Allowable next actions:

+
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
+
+
+

+3.4.3. BZ2_bzReadGetUnused

+
void BZ2_bzReadGetUnused( int* bzerror, BZFILE *b, 
+                          void** unused, int* nUnused );
+

Returns data which was read from the compressed file but +was not needed to get to the logical end-of-stream. +*unused is set to the address of +the data, and *nUnused to the +number of bytes. *nUnused will +be set to a value between 0 and +BZ_MAX_UNUSED inclusive.

+

This function may only be called once +BZ2_bzRead has signalled +BZ_STREAM_END but before +BZ2_bzReadClose.

+

Possible assignments to +bzerror:

+
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
+

Allowable next actions:

+
BZ2_bzReadClose
+
+
+

+3.4.4. BZ2_bzReadClose

+
void BZ2_bzReadClose ( int *bzerror, BZFILE *b );
+

Releases all memory pertaining to the compressed file +b. +BZ2_bzReadClose does not call +fclose on the underlying file +handle, so you should do that yourself if appropriate. +BZ2_bzReadClose should be called +to clean up after all error situations.

+

Possible assignments to +bzerror:

+
BZ_SEQUENCE_ERROR
+  if b was opened with BZ2_bzOpenWrite
+BZ_OK
+  otherwise
+

Allowable next actions:

+
none
+
+
+

+3.4.5. BZ2_bzWriteOpen

+
BZFILE *BZ2_bzWriteOpen( int *bzerror, FILE *f, 
+                         int blockSize100k, int verbosity,
+                         int workFactor );
+

Prepare to write compressed data to file handle +f. +f should refer to a file which +has been opened for writing, and for which the error indicator +(ferror(f))is not set.

+

For the meaning of parameters +blockSize100k, +verbosity and +workFactor, see +BZ2_bzCompressInit.

+

All required memory is allocated at this stage, so if the +call completes successfully, +BZ_MEM_ERROR cannot be signalled +by a subsequent call to +BZ2_bzWrite.

+

Possible assignments to +bzerror:

+
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
+

Possible return values:

+
Pointer to an abstract BZFILE
+  if bzerror is BZ_OK
+NULL
+  otherwise
+

Allowable next actions:

+
BZ2_bzWrite
+  if bzerror is BZ_OK
+  (you could go directly to BZ2_bzWriteClose, but this would be pretty pointless)
+BZ2_bzWriteClose
+  otherwise
+
+
+

+3.4.6. BZ2_bzWrite

+
void BZ2_bzWrite ( int *bzerror, BZFILE *b, void *buf, int len );
+

Absorbs len bytes from the +buffer buf, eventually to be +compressed and written to the file.

+

Possible assignments to +bzerror:

+
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
+
+
+

+3.4.7. BZ2_bzWriteClose

+
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 );
+

Compresses and flushes to the compressed file all data so +far supplied by BZ2_bzWrite. +The logical end-of-stream markers are also written, so subsequent +calls to BZ2_bzWrite are +illegal. All memory associated with the compressed file +b is released. +fflush is called on the +compressed file, but it is not +fclose'd.

+

If BZ2_bzWriteClose 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 +fflush the compressed file. You +can force this behaviour to happen even in the case of no error, +by passing a nonzero value to +abandon.

+

If nbytes_in is non-null, +*nbytes_in will be set to be the +total volume of uncompressed data handled. Similarly, +nbytes_out will be set to the +total volume of compressed data written. For compatibility with +older versions of the library, +BZ2_bzWriteClose only yields the +lower 32 bits of these counts. Use +BZ2_bzWriteClose64 if you want +the full 64 bit counts. These two functions are otherwise +absolutely identical.

+

Possible assignments to +bzerror:

+
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
+
+
+

+3.4.8. Handling embedded compressed data streams

+

The high-level library facilitates use of +bzip2 data streams which form +some part of a surrounding, larger data stream.

+
    +
  • For writing, the library takes an open file handle, + writes compressed data to it, + fflushes it but does not + fclose it. The calling + application can write its own data before and after the + compressed data stream, using that same file handle.

  • +
  • Reading is more complex, and the facilities are not as + general as they could be since generality is hard to reconcile + with efficiency. BZ2_bzRead + reads from the compressed file in blocks of size + BZ_MAX_UNUSED bytes, and in + doing so probably will overshoot the logical end of compressed + stream. To recover this data once decompression has ended, + call BZ2_bzReadGetUnused after + the last call of BZ2_bzRead + (the one returning + BZ_STREAM_END) but before + calling + BZ2_bzReadClose.

  • +
+

This mechanism makes it easy to decompress multiple +bzip2 streams placed end-to-end. +As the end of one stream, when +BZ2_bzRead returns +BZ_STREAM_END, call +BZ2_bzReadGetUnused 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 +BZ2_bzReadOpen again, feeding in +the unused data via the unused / +nUnused parameters. Keep doing +this until BZ_STREAM_END return +coincides with the physical end of file +(feof(f)). In this situation +BZ2_bzReadGetUnused will of +course return no data.

+

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.

+
+
+

+3.4.9. Standard file-reading/writing code

+

Here's how you'd write data to a compressed file:

+
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 */
+}
+

And to read from a compressed file:

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

+3.5. Utility functions

+
+

+3.5.1. BZ2_bzBuffToBuffCompress

+
int BZ2_bzBuffToBuffCompress( char*         dest,
+                              unsigned int* destLen,
+                              char*         source,
+                              unsigned int  sourceLen,
+                              int           blockSize100k,
+                              int           verbosity,
+                              int           workFactor );
+

Attempts to compress the data in source[0 +.. sourceLen-1] into the destination buffer, +dest[0 .. *destLen-1]. If the +destination buffer is big enough, +*destLen is set to the size of +the compressed data, and BZ_OK +is returned. If the compressed data won't fit, +*destLen is unchanged, and +BZ_OUTBUFF_FULL is +returned.

+

Compression in this manner is a one-shot event, done with a +single call to this function. The resulting compressed data is a +complete bzip2 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.

+

For the meaning of parameters +blockSize100k, +verbosity and +workFactor, see +BZ2_bzCompressInit.

+

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.

+

BZ2_bzBuffToBuffDecompress +will not write data at or beyond +dest[*destLen], even in case of +buffer overflow.

+

Possible return values:

+
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
+
+
+

+3.5.2. BZ2_bzBuffToBuffDecompress

+
int BZ2_bzBuffToBuffDecompress( char*         dest,
+                                unsigned int* destLen,
+                                char*         source,
+                                unsigned int  sourceLen,
+                                int           small,
+                                int           verbosity );
+

Attempts to decompress the data in source[0 +.. sourceLen-1] into the destination buffer, +dest[0 .. *destLen-1]. If the +destination buffer is big enough, +*destLen is set to the size of +the uncompressed data, and BZ_OK +is returned. If the compressed data won't fit, +*destLen is unchanged, and +BZ_OUTBUFF_FULL is +returned.

+

source is assumed to hold +a complete bzip2 format data +stream. +BZ2_bzBuffToBuffDecompress tries +to decompress the entirety of the stream into the output +buffer.

+

For the meaning of parameters +small and +verbosity, see +BZ2_bzDecompressInit.

+

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.

+

BZ2_bzBuffToBuffDecompress +will not write data at or beyond +dest[*destLen], even in case of +buffer overflow.

+

Possible return values:

+
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
+
+
+
+

+3.6. zlib compatibility functions

+

Yoshioka Tsuneo has contributed some functions to give +better zlib compatibility. +These functions are BZ2_bzopen, +BZ2_bzread, +BZ2_bzwrite, +BZ2_bzflush, +BZ2_bzclose, +BZ2_bzerror and +BZ2_bzlibVersion. 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.

+
typedef void BZFILE;
+
+const char * BZ2_bzlibVersion ( void );
+

Returns a string indicating the library version.

+
BZFILE * BZ2_bzopen  ( const char *path, const char *mode );
+BZFILE * BZ2_bzdopen ( int        fd,    const char *mode );
+

Opens a .bz2 file for +reading or writing, using either its name or a pre-existing file +descriptor. Analogous to fopen +and fdopen.

+
int BZ2_bzread  ( BZFILE* b, void* buf, int len );
+int BZ2_bzwrite ( BZFILE* b, void* buf, int len );
+

Reads/writes data from/to a previously opened +BZFILE. Analogous to +fread and +fwrite.

+
int  BZ2_bzflush ( BZFILE* b );
+void BZ2_bzclose ( BZFILE* b );
+

Flushes/closes a BZFILE. +BZ2_bzflush doesn't actually do +anything. Analogous to fflush +and fclose.

+
const char * BZ2_bzerror ( BZFILE *b, int *errnum )
+

Returns a string describing the more recent error status of +b, and also sets +*errnum to its numerical +value.

+
+
+

+3.7. Using the library in a stdio-free environment

+
+

+3.7.1. Getting rid of stdio

+

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 +BZ_NO_STDIO defined. Doing this +gives you a library containing only the following eight +functions:

+

BZ2_bzCompressInit, +BZ2_bzCompress, +BZ2_bzCompressEnd +BZ2_bzDecompressInit, +BZ2_bzDecompress, +BZ2_bzDecompressEnd +BZ2_bzBuffToBuffCompress, +BZ2_bzBuffToBuffDecompress

+

When compiled like this, all functions will ignore +verbosity settings.

+
+
+

+3.7.2. Critical error handling

+

libbzip2 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 +BZ_NO_STDIO set.

+

For a normal compile, an assertion failure yields the +message:

+
+

bzip2/libbzip2: internal error number N.

+

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. +

+
+

where N is some error code +number. If N == 1007, 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).

+

exit(3) is then +called.

+

For a stdio-free library, +assertion failures result in a call to a function declared +as:

+
extern void bz_internal_error ( int errcode );
+

The relevant code is passed as a parameter. You should +supply such a function.

+

In either case, once an assertion failure has occurred, any +bz_stream records involved can +be regarded as invalid. You should not attempt to resume normal +operation with them.

+

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.

+
+
+
+

+3.8. Making a Windows DLL

+

Everything related to Windows has been contributed by +Yoshioka Tsuneo +(tsuneo@rr.iij4u.or.jp), so +you should send your queries to him (but perhaps Cc: me, +jseward@bzip.org).

+

My vague understanding of what to do is: using Visual C++ +5.0, open the project file +libbz2.dsp, and build. That's +all.

+

If you can't open the project file for some reason, make a +new one, naming these files: +blocksort.c, +bzlib.c, +compress.c, +crctable.c, +decompress.c, +huffman.c, +randtable.c and +libbz2.def. You will also need +to name the header files bzlib.h +and bzlib_private.h.

+

If you don't use VC++, you may need to define the +proprocessor symbol +_WIN32.

+

Finally, dlltest.c is a +sample program using the DLL. It has a project file, +dlltest.dsp.

+

If you just want a makefile for Visual C, have a look at +makefile.msc.

+

Be aware that if you compile +bzip2 itself on Win32, you must +set BZ_UNIX to 0 and +BZ_LCCWIN32 to 1, in the file +bzip2.c, before compiling. +Otherwise the resulting binary won't work correctly.

+

I haven't tried any of this stuff myself, but it all looks +plausible.

+
+
+
+

+4. Miscellanea

+ +

These are just some random thoughts of mine. Your mileage +may vary.

+
+

+4.1. Limitations of the compressed file format

+

bzip2-1.0.X, +0.9.5 and +0.9.0 use exactly the same file +format as the original version, +bzip2-0.1. This decision was +made in the interests of stability. Creating yet another +incompatible compressed file format would create further +confusion and disruption for users.

+

Nevertheless, this is not a painless decision. Development +work since the release of +bzip2-0.1 in August 1997 has +shown complexities in the file format which slow down +decompression and, in retrospect, are unnecessary. These +are:

+
    +
  • 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.

  • +
  • +

    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.

    +

    I could have changed to Sadakane's algorithm, but I find + it to be slower than bzip2'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 + bzip2-0.1's performance on + repetitive data, so perhaps it isn't a problem for real + inputs.

    +

    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.

    +
  • +
  • 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 + decompress.c 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.

  • +
  • An Adler-32 checksum, rather than a CRC32 checksum, + would be faster to compute.

  • +
+

It would be fair to say that the +bzip2 format was frozen before I +properly and fully understood the performance consequences of +doing so.

+

Improvements which I was able to incorporate into 0.9.0, +despite using the same file format, are:

+
    +
  • Single array implementation of the inverse BWT. This + significantly speeds up decompression, presumably because it + reduces the number of cache misses.

  • +
  • Faster inverse MTF transform for large MTF values. + The new implementation is based on the notion of sliding blocks + of values.

  • +
  • bzip2-0.9.0 now reads + and writes files with fread + and fwrite; version 0.1 used + putc and + getc. Duh! Well, you live + and learn.

  • +
+

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.

+
+
+

+4.2. Portability issues

+

After some consideration, I have decided not to use GNU +autoconf to configure 0.9.5 or +1.0.

+

autoconf, admirable and +wonderful though it is, mainly assists with portability problems +between Unix-like platforms. But +bzip2 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. autoconf doesn't help +in those cases, and brings in a whole load of new +complexity.

+

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.

+

There are a couple of +__inline__ directives in the +code. GNU C (gcc) 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 +#define +__inline__ to be +/* */. One easy way to do this +is to compile with the flag +-D__inline__=, which should be +understood by most Unix compilers.

+

If you still have difficulties, try compiling with the +macro BZ_STRICT_ANSI 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 +bzip2's checks against +compressing directories, symbolic links, devices, and other +not-really-a-file entities. This could cause filesystem +corruption!

+

One other thing: if you create a +bzip2 binary for public distribution, +please consider linking it statically (gcc +-static). This avoids all sorts of library-version +issues that others may encounter later on.

+

If you build bzip2 on +Win32, you must set BZ_UNIX to 0 +and BZ_LCCWIN32 to 1, in the +file bzip2.c, before compiling. +Otherwise the resulting binary won't work correctly.

+
+
+

+4.3. Reporting bugs

+

I tried pretty hard to make sure +bzip2 is bug free, both by +design and by testing. Hopefully you'll never need to read this +section for real.

+

Nevertheless, if bzip2 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.

+
    +
  • +

    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 + bzip2, and I've run across two + such examples myself.

    +

    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 + -O2 + -fomit-frame-pointer + -fno-strength-reduce. You + should specifically not use + -funroll-loops.

    +

    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.

    +
  • +
  • +

    If bzip2 + crashes randomly, and the crashes are not repeatable, you may + have a flaky memory subsystem. + bzip2 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.

    +

    Try using a different machine of the same type, and see + if you can repeat the problem.

    +
  • +
  • This isn't really a bug, but ... If + bzip2 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.

  • +
+

If you've incorporated +libbzip2 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.

+

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:

+
bzip2 crashed with segmentation fault on my machine
+

and absolutely nothing else. Needless to say, a such a +report is totally, utterly, completely and +comprehensively 100% useless; a waste of your time, my time, and +net bandwidth. With no details at all, there's no way +I can possibly begin to figure out what the problem is.

+

The rules of the game are: facts, facts, facts. Don't omit +them because "oh, they won't be relevant". At the bare +minimum:

+
Machine type.  Operating system version.  
+Exact version of bzip2 (do bzip2 -V).  
+Exact version of the compiler used.  
+Flags passed to the compiler.
+

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.

+
+
+

+4.4. Did you get the right package?

+

bzip2 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.

+

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.

+

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, zlib-1.2.1 and +gzip-1.2.4. Look for them at +http://www.zlib.org and +http://www.gzip.org +respectively.

+

For something faster and lighter still, you might try Markus F +X J Oberhumer's LZO real-time +compression/decompression library, at +http://www.oberhumer.com/opensource.

+
+
+

+4.5. Further Reading

+

bzip2 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.

+

Four documents describe essentially all the ideas behind +bzip2:

+

Michael Burrows and D. J. Wheeler:
+  "A block-sorting lossless data compression algorithm"
+   10th May 1994. 
+   Digital SRC Research Report 124.
+   ftp://ftp.digital.com/pub/DEC/SRC/research-reports/SRC-124.ps.gz
+   If you have trouble finding it, try searching at the
+   New Zealand Digital Library, http://www.nzdl.org.
+
+Daniel S. Hirschberg and Debra A. LeLewer
+  "Efficient Decoding of Prefix Codes"
+   Communications of the ACM, April 1990, Vol 33, Number 4.
+   You might be able to get an electronic copy of this
+   from the ACM Digital Library.
+
+David J. Wheeler
+   Program bred3.c and accompanying document bred3.ps.
+   This contains the idea behind the multi-table Huffman coding scheme.
+   ftp://ftp.cl.cam.ac.uk/users/djw3/
+
+Jon L. Bentley and Robert Sedgewick
+  "Fast Algorithms for Sorting and Searching Strings"
+   Available from Sedgewick's web page,
+   www.cs.princeton.edu/~rs
+

+

The following paper gives valuable additional insights into +the algorithm, but is not immediately the basis of any code used +in bzip2.

+

Peter Fenwick:
+   Block Sorting Text Compression
+   Proceedings of the 19th Australasian Computer Science Conference,
+     Melbourne, Australia.  Jan 31 - Feb 2, 1996.
+   ftp://ftp.cs.auckland.ac.nz/pub/peter-f/ACSC96paper.ps

+

Kunihiko Sadakane's sorting algorithm, mentioned above, is +available from:

+

http://naomi.is.s.u-tokyo.ac.jp/~sada/papers/Sada98b.ps.gz
+

+

The Manber-Myers suffix array construction algorithm is +described in a paper available from:

+

http://www.cs.arizona.edu/people/gene/PAPERS/suffix.ps
+

+

Finally, the following papers document some +investigations I made into the performance of sorting +and decompression algorithms:

+

Julian Seward
+   On the Performance of BWT Sorting Algorithms
+   Proceedings of the IEEE Data Compression Conference 2000
+     Snowbird, Utah.  28-30 March 2000.
+
+Julian Seward
+   Space-time Tradeoffs in the Inverse B-W Transform
+   Proceedings of the IEEE Data Compression Conference 2001
+     Snowbird, Utah.  27-29 March 2001.
+

+
+
+
+ diff --git a/src/misc/bzlib/manual.pdf b/src/misc/bzlib/manual.pdf new file mode 100644 index 0000000000000000000000000000000000000000..f043e164ae04d974e992a25100fd46c348478478 GIT binary patch literal 288134 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 aV9~j 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≈Z{nnzLNJMfs7?X3y}T5@O7dJa>L`t( zYAb2FFS;QL+&pkLDGAofY*FwvC+CzM>#`vU`Emeh5KY}ih7Q0R@`ff#IL>ZDplcoY z5naSGFon`S9T07rAbn6 z64#cAqcQ#!kRk2)h@FNe4SE|XsHC?n-NM~l@jmIqyVZ|!^ZN6Q_`uoC6O+<~-$a?c zGY|J^fZmSXIIepnh!wJ_q`L(!+Bb? zuUv6?tI`W7dpe?^Iog7sG?N`#X7^K+pcqp2dzYT${2m2sTy2q0gTZc7?HU=n6;uNo z=4yOc1T$=h2}+kLX*U(kRtt^VxE1^RE6kJc^YwUE2fZ@pg}j>IL-uvOrEyXZKrW`a zyrsPRIA+*zR3=rxZUegzp{^KJUeUbk;FX-WJFAVha0#-M$m#&4rG?Ld0`X@i%kQ#7kZ?#}S%keDNonYUI$0;7$9@xsoYW$>U|E*U|wPAg_D@8sIhL{Qdo z8lNPrYsO1u42+2a!eJz4O}02BuE{q2pe8Ye)3_4!x*jm1j1cO$BS{nwFz5qP@yBu- z3%Ekwf+XhrKW#})i%8$}4~|QBn|nCRs7TVg&AF|9eTev51YHN<&+<|l{(iW##$Hw9 zFqpwxx$qoCx=iX)>>8OSq|9l&x5)qpGiRfkn-vat?N91!(<}(g=yO)7?V_gh0k9*0T;CRGIoDpb6w?0R> z)OR{F26Hq~mk9!HM$@or~Yq-rq_uopI2@lB*mzZeECOyTz( zgr!_6ghqxieP_%-5g)sDA41{6?*~%zQ!}=7=Y45xTy38RC?_}J$VG3f?UZDb>F$`- zj(F|+Pag?c1a$cu2jZBLu}O2u(@xon1IS#Rqqg(Gf`F;qU!^T@Hg`Jb z4$OcHR-7jrCG^>P`*C}HAiGGsrOQwzsEPGv9^&5G;+?bO(JGh1y0)6gv0k z>uI}`z$ugyO=@EpQKBh-tVO$McVWW3yjoS?wrw3IL-5&hh@q|&$Q0C$OSZh}e}Yg< z)E2ca=^P_uz+xbs*(V>zkG7v- zp91n54A<2|31bbtT%}sJE4f`C`#DzUkCIhb8NyO6jLPSECa(kF?&sy4BAH!UK&a8V z4QvoW?+0fn0;o;hunIuTqdAoYTaQ__*P42gFhfnd4V)mk6}ka~Sbo?mhRmbX8UyUh zVHrL@vG2y$Hraq|pV8qZt68WFDs4N_A zgrLVr5T?}IH(Tn^7~*mox(ZR}V1NM4W;k9vR2BMJGuFviaVK}!`-Hc_o83B{BBZ&_ zt3uxwcl;C^S0Sk_;{7HPEbhqtRi2qleC0uP%fNIfM4Q8C6xZ*Wp^t;cBa`a}Je+ug z0i>3^??@UhERF|fjpUN0>OR6eA@0eJ#W#sSpM14+t+ohP z>69Pa&VRoH$*xTis*6d4+J1QUh)yFTU%x3dQ4x$l+}IcmLy%{KD2lp;wBL#Vv{$?lz7MZn*2D%oQE{|x$!IB zN9-qG&nFT9KUZui6Nt6liFL%A9{>~$aNB>gFEerc_avCVtiS*Nn54hl#Q(N0Gcf+s zzx=NVJjj3em!%YxWmN_LgGrLHvz4Y1w6iw;+i?63BQq1nUsTFJO}~G){1+oLE8~}Q z`9F=!EG%DR|EH0e@yne1pGM~Y+sOZPG=F`OzX_x-xagl|<}c*w9|#gN(_aJ<`&YOf z13o+3UjcppgO~ZQtd>8iDq?gJUpXp@|4L9%`^rxFM;OXKF{J+qLh}5l75Z-%@;_&V zmE}L81|YRq{{`~=zks2?di?Y8_u8N5KcD=woxhiV`u}IIKkxt5|Nrdsr|+NTfA;vh z=b!dJ%m3c`&wcnebj0wlAjLmN{*U*Xjs34*-B+fGvpM4z3&#G1jQzd#U#O$MX6S!w zy;k&5Rx&|X3rLvazA@OjIwjGzsqz_PWd*_>+3%;Q`<5R&vBA|+x6w}PR`U%gK2;zs z2^tMSFFk-flQ|7M3B(E07l5)(I?msSJUkx#yJ<>V3DUcUpG(^%-{tL_@AU24#ifVE zrUGO#avy6CBQ%LRH>(_w;Qoz0E?TS`ZHiz)@ODi&KfQBlxIc+M87h=OkO0(E1fUu* z0(CNkFft}Y?;R=jmsbIRCx}575wH|?2%!-Y)Da~P`g8=>G6|KOo&^Yrlr`3}5#O_e z5JkAZls+3w$Qm*R9A8+*AI2W>yCVBudY=LenDF#`tiUIbWZ<>3B62R5F(Uv4VxN5F zH~yL*eHsCA^ZJV8-2_&KPH6(=I(c(Z&2H@XY}!Ra4aI!usj_zX`q(235JR(J3+hj; z>>SVpU>m~BnerA0jmR={eg1>DCQd#%zvGlK41@B>gXGD8qa-sRxo+qoWt0V9e$VuV zL1*Gk-)R{WCcs0$_{I+ghffZI1!zr-;_3PW%hcNC%TK&*`vIk3)8l|n@^uZ(`9!2b zK-|e-1)`kd0ap6F+r?-$&PGKeFR5~oHgcgg*+*+SYlO@C+H9+J=h7FWy8CC)Z@AX4 zGT_1w?dg}IxZC`gy)q{V7R59|y`!hj^^>WClbGa|FZ)-|ZiP^U4rBoiD$vy(r zUD+H@fz$SCzrLmXI(X++0KK>Ea#~!BF6lNdGS2C?$mznmIc8Eql*CF#>to<^JGaKb zQU9T0_|R#_y~l_3@H8oF)3%v?vj-i~lB;~-JcxK@jG1Dv;G9!(6|RK3vg}O|EiYa? zg`yixQSUFI3%Hrg5+GI?cjKkx^$UF$*KU0Le5W;I(x7&y9B;Ce)=f=qau$qwO)3j| znWfTZ0W_a%>$FlU=`>q$c?@o4aDEwWE*}YxuLy?bZRXjaZ)GJ)F9$^)3w#k{Gr<%u z6LI{G3Rbd!>5_iRp_DeIX{}>Vc{FE}uu#B&t(cC2y|NvCAU68N31vZybk?~`=)PLP2qc( z-xMo{hYg=>C5^-D5XDosbVYBnpG9J(aCC;5#g(63hk!e6OqLadaZ$sdI9Aqz z4h@gndy&i^wMnO-AJ-Dyjo=p%oAqpa1!ukBYCgX^yR!+?HaAv@icf^t((1Eqd=^?K z=r?EE%#EN6WYZr zW@aIECaE!*%O9m{D8p=XY!bYfL-;bIenp=^HH||2N|A$8NjGBG=**IWh3X7DAVNV@ zzV>`VIM0_*s^W@yGtA!LinOC>MJ9bIwgyMOGxAvYC3a8%sAE&`13TvO@-U}+sYbmj zj!&zET>5UIFe9?Ex>#$iD|JuP6xv|6nH8iNhK5>kz6r`m$MQti>eNmnD%_IqgMEG_ zXZ&c@>AY({c_AK6yP>pToauTLsM@4GR}Ph@(tOn{Tkoc*b#tTW)#)HZL`d?av{|$> zGtC6eNY~4io1Vu&G*VfgjuwZ?sol*wta$1e$jr+&^Qw%!=Rh&q`X=~;74I=krxc4& zQWc`}=)K(v44Ei{H4*3R`m+=dR#kW(j)un4N|rAtDk2^>WbjvtmEX$3x`UskYmw=_ z%VF{wa0u!hZv}dW9?L^L3x90;wY7Y|_)?B)XjJ=PK@lKbisqqir-8Yl^dsS+f<`=>*4W1VsnUJ{3{&a*eA>f63l|8dN5L|Y;cLZFF1jx$H{*aWeop{ z7XEX-`(H9;|B*)gpG+C^7mf9AQO5FhcKkO}_7@SX_)kqHDK0FdsQAT{$w>SUOc}%9 zdB*>sp8sz7vx9%QaE`zD>;L4!|6feme;M$f3XF!~iz)ls(tm*9UwZEUhLkZeeyOl8 z$oeZDmL30#X#1aK*uTIob2~e$zvI3B&ei*;ruti5{GXcYuNnIKdXQRwpy@xlj4IlUzQFuuQtY)Rn>E+LrdFfBUNmKe zXDJUhB}gvccKN*AvFrKywN1yc47HI}g;{Mn#qbOflBp`^p|Liyu_n}jx6Cjx(O<(; zsIOwQbB?b8?;j;iQfr5OK&~2$jEZDUL~2)@0UCIThwD?fu0zj z;^)--;M~YT&dQXk-=grtp&yORxs3KF#j##nH@#mYt*9!186g@IT#BC|Mg~HfCI{CF zrpHIrJK99==!u?13#S$!^#>C$Cm|UV6cL${7L(cUug}$f9#8o#N!)d-*zIrYpFY#s zz4~dqS7TRbXHHsAV(6!8d<-!=JY%i(K?3wYP3MXOPn?IPrhU+`xwt&RWo4wzcVi0Q zPfy5y%Jhva;Od`B7+adc_W#tsykR3oSp38phyL^-{$!JX+Y-F;gX;XW+y79D{%DqZ z`}EBDq-qE%udMtYx3LBI^!T0NrQP5xY(Mm4m7z&g_7l&Ei0iAc#%Ex^AIk#$t6Tgh zANw4ws9y#Fbj_0#1QPIkcd+UdqAIRwakwfiX|nL4Xp_WKqklmD@w%m$m0Bt zo#AIavWM6Fr^^$#knq4};7G>DB}}22!2$8^6IN_Q+Unyc{J9?e#HU9xo1;VB4gTD- z79-MaH{@r|v|sk!2UH|`&%owgj)sB*15oM*PW30rlbFr!$^Ko+qTj|-H|Xc^vtFRB z>7jusP<^eXT_2WVR$SKcoPQc0D^W2Ma}P8p>WTbjg{C61yxG=e4npm;j?I$>-q;M| z@NLPw)4}@Asr-*ab3=gsA zK#BLG<;eIt-&Hb@4{f$`q=iW+7l2YN1pv&|df@Ll5}r!jo^Xm#@RCB;&!8eV$Ky-~ zBl}M)=ASrE+XS>Wy4=hh)mZ4lX!wryms$Ej*QrK zo^L zupnqi)lY}7L-2c_jNI1!VDNkFk;{02;+Xg5DfwYdE%M{G>5A#DUNzdVAepOnN29fN zdr8YC*n(ni4vJ*jw)@n)nLxX4Koah!*`c`%&dRSyv7uzg#%$MClEsw7u&z1T0a>Z_ zq*!eSM!pN<7Kl0!MG)w{qRdkJtjpV-1nL+a07=n%jof98)KdtsZxelrwHiGvL@=f* z1ZkBuS*D}pMrI*s{BxwVN#~ zIn17UXeKC$2P+A(QXyH;CMn8N|6P!Tx4uY}Y4*L|D8a@Rddq=f9hdt{|gH^>LzUL2nv-v71c zR7dT%PA0qS{7te$CdRkCtE;)b^szaR!^Vd#{i1yp*Du60X8Wg?k=@->Of=)V+b}F? z+No)K3m^IA!^<*+i@da0YS-TGerW#?oxns6cY?vLrdHBjMkJaA^1_1k**jyL-A}zE zSZBC>4EI6MS?Uj8a7>D%l3wIjW6RaD52Fmx^TDjM57|9bouoYu$ju8n2w-+#9L?f= zuqnhf2DLqWDXPsGwzzt!%o9-!IgR<&)WOByCPriGuF00x3gV@-tk(BOUK7$`1s0)f;*{IDWX9N-y_nE0Og)KOqa7A4>0A7p}r4RWxrs1nM)iDi^Y_dj`aaJZS1r&;A ze@pDw-I3Vt@B(Zw9u>DMB~0Co!q+fTkJIFdEg$?i;}7`?DM6JGRJu=K1qGIW>O zueS(P@!?2`qG-^y>`l(0h1}`VuR`7{59vvWLCaG#B#6rh+m#)Wx`5MGTS9J-a^J}03*EHhdxONUjoIRF z5iXG??$$X0Yc6}K#q8kId*y2EsUp#K-MOMTQXW$GvMlG!!2q?h8#rG>iBw)IXq|-T zc91z!CQ?x-VsD*|K8`ypZ>l|C(`f2sm5Sm<+anoEkW8BTXdDWba!Fyfi2>f%9-<+< zhsa04%( z71urCfO>6xjs)DAbIsUiY@OeEl$A=F;b1g&+b-7fmJ4Me z@wY34e{=mr;tWWZl(n`DIPwXHUD61_#=GjxM{;b@ys4oGf!iYHi_Y(_0|!-WUAcF1 z9A3q@m&h%uSp`QBp2}`=T&XDh`ZKj!FjL}=z|FgRJFD?Af&P|Qbe_N);WkX#vr6Pq zPTl_6Fv0CdGx8pX>#|}ilE~Vm=>@$$c0tXM^K1X7k^OTt>A2%21*wLCYO`H{7q6^F zYc+2DPw2Z9q-s18NIw|#fqOU&LtAw({BX$7Nth^`m;FNzOGscqFCTc%a6G@Ayol%Pacq0JN%mNt z9f>*RrU!p<^_c|U{{1sUlBH*GwV4o3QvQuRk)yc1)S{84Ug{>Rz*)v#YWQ8hU4=r? zJ|MVzYTacWAd~jbn@x43wq6>y8}Ci}8d%j$74~)6F_w6nDfkf2V)&yoC`&;k*3vYu zZyw^Dm6H72_|Za~1ymLp%!U9DfM-h^ns#N(4Z4Ff2OS#p^T~-CnX2=W*`vo|Rc?(( zU1;1xKJqZQGk4U5e6v)H+nL5i3o#FV3x}kt?Wf;Zd@+M9kHJtjL$Rf|?|&=Ib{d4To=ZQT@nHX#!Dw`Mg-U<37R_;ZwuiUBxF4);;}HH zFKMT;l;unEJqKbd#Ip;KTH)66pf8PR@aPl3G2!^x88!U7z&5h4AjZNKxmq z8IV-XvLF^;bzy*Pd(VF=_QCzF9}J6XkkIiNbfM4R@BZ%RZjM*6fmV=7eCL?S3}wo0S@w|MO;sJPdmCIIim-%tjr2yp2OyQX`C zt!O`$*5uRN{4-FoQ9GA*Of>gBMyau7s-mUq+9XwZS3BPpJc;KN6YiIDGXaVvnB{{a z2exGt3J#epSZ%jXN)DRyYKK!GhU8Z@g}Dj8Z<-YwVsJ(#)0SmKXTt6|mjWDX;$Na_c&YozN~ zHwN~d2>cyOYmS(?DSy!2L#XLQ_;zO97$^YEsYI?5`~ofrBylm1m;H%8`Re|qotU0x zk(4<*+B&Ny3xx?ci(!?mp!|@WD4e+;&3Ma#!`AL&(Un=dSu@wtr5H=+TF|lPOrX+1 zti8CFtp?37SZ#NHik7>v58Hh62zn!@{q5y}N6S-_+uMpal{`xhRB08umvZ;vTB zR+Jb9oA-*38PaD+SDQD|M?9`RHY0BKd+N0&>+K!P8pdQjDTd<#Uo^dHF3CgFcuuk{ zT}4^&Y|$Kn63|+@(KAg&qN4+F;a!j0!a7fr3GkuAdKGS37P#3+8)6tWp1k=tZoFYC z8OFnUEck*Z$PFgzACB@fC+k6QbT|8(l5%w*R8F;eA3Y!i0i7UKbKsDbk%lW~OE_@> zZvnv=zw1Ae;F+2@M!B7dARf%DF7(R@W|%K%y1&^%nn1>IePP%U}0eCWP*=@{eNE9*%9#mYXuM?2sB@nw0Er%qe)8X>8$cdGC z_oWMuQ)(?>4g36ckEX1QmzCs;)36Wizt%d^<+CZfVmpR&Kab3*I~5Ug5js6bm)S+L z$$~Q{-8?*M7zjr&f56K9O}e0Z9KP zNCCTBKIhJ?6R^5`ve~{->YJ`|SDy||!g=bvMT<97#o79Jz!`lF6QP}wP?*1?jNu#5 zJK72QOd+;4@y=AXjdac>lY@7#-88|Gpt3h=Co(Q!4_y*Hx@)NC|Bi}r3D1q>G^8bFlWTcv zH0mQ$0C&5UL#KQjL9VRNnUPB2VUQvGmcZ`<7#<*B=i~s&AYifNm zw0)}p;Uc!aF61M6F<`Kq2`G0J%HnuRQLwtR20_JW#oZMqj^caTav!bO<)jWA3ZX}$ z_YJ$G;A`x61MxEa??1d$htp@ygNsmHLLxZ1%=BEh2XkV4!1jUqa^|{29|w%Xj##P4Jsyxl;&eMuo~l612$@V^Rh=XtdWJljWzDx*V+cFU){-aMB`A>-)j># zR+jBETcG%n_&4_Bii6!*hVAj<%6IRvJAYq-X0)=h_}!?$FEKN%&7Ps`9lhvW>lHAD?=T zY!B#mp-}R6S5#ng%|t6h_wiaMLH-F zblbIj{}IjctQu~gtQJsgYyDAO&-me(L2Sz)E0EM7k=DXsUdX~|yN^Gx;bH#y0T53u zskn3M$e1BoV^zNSe91y9xG@c=*x7mLq9U~TeJ{xc2tkE*X@-^tS1+4=1&Woj6Q=X7 zv>U5QhFM*(0_NFWidA#LUJwy9betxd-QR<+6Uw!DJ#AJFNWGG{5-CN*{Y`B1!+6vE z+$p#j7bskqk`AjUR??OJENl|$+vOH|+(uRhm3$*lZ80;yU4_;TeAv>m;K|JR9)(G&+ z08*szwWgC^NHXsp@{}_E2zxXz0bM;_M96*Pi;IT7TA}1)l{TnN`RQKrejbf6|La`g zWsRp7eK!iDMsLT5vf3{hk6pc;{}hU6(?zagj1JzuKF8AyVeEiRiD_(N{^cAQhmEN* zjdRA>bUMz4Z!mL#(&-Qx%$^J~eG!Zh0?>nIXTKceRc7~4Dm$6dfv=OUG+>gplE~wt2)j-P0<$nVy4z33eIyBx;G+mu_yE_#_;OF2 zAP&2?QUNw~-tT>wST;7HxturpfS6n%*Oq1|J}-3x218Gfkq+`SgR+9H{QINd;VyS# z?OROm6rriPBj=pMiXMQI^;U1HJt-V#+l1VDeY|t%tYvxFofIxA{Q`eZE8xmNq_n*b zvgL*3F~xDaE69@Ip2OoMp{2>YRh^YD8p(Pn!rkQeIw+l$5+ukafJhly(=xu_!FNOk-x`jT zJZ+y|Uyx<5k2GKiw;)XOHD*xWng;Qp`CUf!@&dO3d2bXUIn#gb(5hi;;*~zfMWBOH51LV*o{Kzb_c)Al6tyEvHpNmY1GW5){ll}B=~mDn%4y6$ z8@LYn8%$TOX}~OnGk!dz>b92f&Z!|4L8YihdPTMqY5g;3#ySVBqQs?|c@+r@0^2Pl zC0+g2gvgn$8eoL3Xu7$*vsRFy5?i^=!sVg4V819ASwM8zwlVe~D^ClY062c$F~@Fl z6ky+lU~qJJDKrqxOi;RXuhp+@5iIeUcEpTzR0^$1Wd~+x(J-k;=n63WDmWmG$0J8B zo`h9%4p-gAk9Ms>r0wS8eVdw>Jzs@{QtmTc8Sfv3!4`0o6@w3p&cUVN$2kHM1lDGc z1UIQ0YpL0BdJ5A|T8NT&&T>`)D}7P3yg@D9XW22Y$xxGb&8IT{oBfkh{8;Xa;|6bM z3j^!8o?q!zl&s~K-?0dkYc$-%gUD{pC>i-GnBX9Ja&nx zkS-(V3m|eI`0~*UXdK17(lGpwW5&ZE5w^Lf zSb!mi!b4)u)f4Y(rO;lH3&7nq~SRuQ6J>XC4%QLc6izlrpnB=NlliGy-(vA)q z`xSVTkLUB|q-9jjqR=D&gbEPylLJGBK&C6sA_aWvW%3GiI>?qq&k?N-p?v_%{+`>&y?VKVajl#>cSTCSp4^8` zj%_W;Nu_pGtK>-ux1w^iK-0=o{2JQ&5^km!!Ne3gvfA2;nj()f=gY!D5$xu6t8yh8f+UT-~Jb>P=Ku04$3aZuZ{OJ;xZi zu3tDYk)v3^A*4fLhORoq8)YxM9yacZdAatSQ&J?TktRpe{URX>V)=| z>8|6t*0i&RKCEk*TTbk29Ko$S2}{?Z^g1bUUA6Q+tV5QO^i~9Du$9co@kbvoKUTmz|#inil6}NnAG{GEo zOq1CemuH#Of<-Yl^qN14b2Dyc9@$7R{|hZY&W@>y6TSd4e}U!{(QiG9-FmX6JsIlZ z$BVVeac|y?RJx3cHFas8L%&JADa?p_4TC zV1`V3?7~j}z+qvraf9@rySsdvOsVkXx@XiSX)uf*b9K+|oD36ZW|GS@a;(Gi@tqdu z#!VyN*6M3P02T|gmujHiIhA0}77%rjF$1Dmdkio;3>uh)F^LjSJvYmEbv-`3bWwMA zykMX8=t-gSph2OWf0pF#47CejC$6`9v|rII6c3CKohkzu9#BG^q`r~u&+A}A{?w-3 ztn`(H$N)$DojT}ocC^8F(xj#?pOMqkreG#Ja$&0p$q~LpT{!MEURqAfv6_-f1RLE4 z2B;Y6q2!{o^wV=-YX7F46};I=LpLA=S|g_M)Dot5MhX&_-Yb;%+d_oX6&Rpz^D-rQ z>aM-OIb5;z$;JL0i;&KerglN9-i4&Onqi762^iLhy@dyt$HQzLUMaU)c5p@vudMbC z$PHyQKhY`1lYoddJU7UOD9W#7SW zv3mI9D;rA=U#v@}Woi>tm*f(Dp-RkL237$mU_ytASK5}FBRc`%bK$MHs9y?!zCYwe z7xwm7o%Bj`9x{v(lgSe2aB`J(vU<1fEwG{U_vmVfKCTlQDjD=M;6N{rN&IrF+IJN$ zK3%{qyVw-Xuds?7NSoJLM=We;oyjpa=efj(4ApFqb-mMt%p-tyPVB6vyQ&)e#( zlG2c0U8LH{mutczy)^n~P_WJ{)aXRn&_G&AQ%aS%-2^_{#E)3tT|==5MI~4v7U==c zTf}CA@C-I}qR|h34L3GeiTAR{a$MO9{6uwYRWs;d;tH?#WHI?A7>*}rXELLAzn&xR zu)}@0eAg~{!T>yXBu9sk?T`^eXj4Tep@CyCkv6SSoPQY~>lr6JKBO994W%O4SU+;O ze>EL7biYh%io1+1qa@grmhJ9%uc zhj~(+S|)iv`GkpcOtaJN0OX6tI)ps)N-vtz~ITwT&5!w!x)2%t> zgU*A9F=$#wMsNUod^p-N+x+5l-L?e0|5?|?wXu3naj^@ztiZEbv0TJ2{&kt192bf~ z-es2)IEPaXwCF-iE+=}9p6l0;H&d{+jq{3>iQr1#i_Bad+*O+&V8WowB6=iHC_Za z@|^%A#!~kqLzpKZcbH2lsLxWJr2}VNB=5WSHu;=eWpZWps%=NA{A&vKjyADUq#kxl zpy_4cGxTJQbfP)fHe8fv5TkxUtk}Kj5e=uHt^h$zgg@bptPQoWj6E zrXk;NWO%xB?pQ6YC~ftGLaK9;_6%T`z&rRe#DNq~jUAMCgmUy@Q@7JPoR_zt``iw-ywKJ`n zjnBlW4;WuniTQ4+EhX6lgDqb_8E(rl%M2ISc==PLr64iHk$NcmC{1~l;J0hh9w0dK zn)hN%JX0Qw*Ypl%DLo>o9F3XGS;Mo`Ys$K5=vFI5ah&b`@}2j5A{-xw$dZ|dZ%LjT zffj2`y4IogJ*X0bVaR6A!;*|NgitSPzu5;8Qu)7M@JFAUOhs?QEcX`|=Q(Xbi=m6l z2lyET=Lu&pV9G2%a%ielZWQJ z7w*G{dbmLVl8YYh5~Q%bd>%@jgp;TK(WtOrw*Fqb_f5Ud0tI-+D)PdD#G}5nA`k1X zmy+6X`7Lhz zbO5UaG|&bn8W!&ga{3l%S*W(wGP!f3J>5E6%bbnY*NyB1Uj4N}X=%3|_4JBN(4+O2 zpd@OqT;)A3tTI+yavk_n=CkUNE6dBwuFGUVIpp2AtMqsWNbvJWc^Rvb4r5B$)y$Bs zOTK65NP_fX8cAnhPZFnZBM%b@#H3G!^k-(Y3S4H$k>h2Q@;<_af_l#z#9XJmHcRTj37{M(jIYDT;h;Tp4YOKryup2i;or#3}#lwA_y z>V4?07Xjm^_G@QK+II|hEI@;UeDTeX-A3!S@+~{}%u9P7;M*jLAOb96?&6~IY-4TK zAo577+MF@&IjIVj_m7APa}6bo4>I&%(8;QDdyh_FyXtSKppt%7#_hQW z=;RU9G6}a1$|ExNRjV_oSOJS0Roy(0qZyI(HyKAVhNmfDjiR!rKUIO3&2YX!N?Ve^ z?58~B00B%>%=Yh0(Q|Csb77x^yQsW8jh$B4j<;eDH{&*aKvoMCi4c}J>fIF3d;PX& z7Q$UuU6r`JMk~gCRDntqzkuzP^*#s*sO}*BSlK$4eCn2f3XfC|BC1X|B09?{R#=o% zqdt*4n=j7N1*V6+VLYw0Dykpa&R6fbRQV2;iUDB(NH*D(Iy*jG6`r_6J3u36uD8G~ z)euEaZvAfeMtsag?ZxH0ndH80NZ0B|Ifdgbh#}`_Koug$&fpy%QTM!@b z$5jwa>fL~`;+B?qw?6t=8=~Urazxbk78fR|Jy_{xrZORQ~83&l&YslqciJx z<(Pqe+At0=u5Tlbyrs_!Fc=%^RU3l7usT?nnl$RC6!Fs9*I@eiAf+x(?~86W74v;d zGmoBeCwNB%*&MPo_^ld_U2SJ@ceAVpdG?RHiS@zf@hnO8i5iMLa`)%%E*`7Or4Jh^ z%XIClmKDB?R#SyF+EG+3x76YBswUw`*_uGcFv;Bu6-SB&tlz8+_w*CljMY?7kP`G$ zu_wYvf!^(Fpu9!nxlu|-muZG;xVGnLz@wuf$!5Ayxlnz-NPPC1BR&^_`y>BJwUHcw z<2Amm>HD#%EvO;T`N!`Tz*L#7Lz&CnxNKsXI<79I_rbUrzUhrHWk_2=Kia$fs!O^q zeG^Boh!&BHOFF84@KJc>=#o=eTY*IeIyrwvpj$lP5j~`C3Ql-oFIvIwPB{sqH zWQ_@}-G7YK_j5-S+?*5leA*O2@=CALOT`QRfVhhYb={Slq5|r#^gW&x%L;DvdTb(B zc9{cx6D`^?N|mL5x-U?JD}_wzzG->pz_ndbo3sJr@9Z0FA%*CL$n426X07t};%1lZ zz^{6m#((16oo)1OVLB%hs%ni?gQ8=HY8$egy0^?IDM=COwRfgPwAEwph)5%esJgj9 zZk0{YPoKxG{Jx#GGQVU$5NCDo`SL>rMn*rsYn!AS>JH@>ZNPd&Jsbb72eyVWR6cio zCV8Tlbh`9Kkl1bZ1l<)lhHT2XWfp4pK0Ha;^x4A(k_Cqn!W!|Ey-s3_4UK?d5pt$E zbLu03^*n*Ow>I3`fj#KY2um(3ocfSGGT*il9)G^Ys&zuB_$toI(Qb?14Eomy20ZBk z;H>2FwCFarb#AedC_Fech-}QY{1(}^Q!KfgCZNA`i=;&qDLpw!x&lrBC4^$4Fhz3h zSg|~HVoNzm%Vgv{S+0FXVt@zVu*dd8GU;M0*8LA=xNmVpDOt5r-;j%bnaZpYq8!;s zg4As>;bRSEb~^%!<_17EfgIGFr>$KQ1H@t1cKau;wzzsp`i64kB{KUorAl%z1pP=R z6a&1Of(m`FpB5U{1Qu9Y3>UnWtg|`g?R=>}i6H9ZyFqT@Y@;!zkI2{cA|H8d#35lFx!o=N(0rVVF+ zzoDPN4}XlhQL`zGR8(XL)_AiSgA+|av5wOgy+MV7>dZ!}U0_aO%jFubBo1E02b$i! zed4RUMB{h}d)zrHBE2Ve<)w2YXl2f!RCY^wRXg2UOSpPTEtN@QH^q{2!E#qgO z(iLZynjD)uEvm{QY1p0rkGFdcvLsj+Mc+23Z5yj?P4`UOwr$(CZFf)Gwr$(C-Ea2U zXP>*zJMTuk7xCi$Q!6X8vT|ict%!<@_5D6375HBvvUj3D=wxrjs)G54&x9gJGKpeR zbcB=pY@w&{F{i;e<>#P-R~UWmgbP316}_If3wZnnls@>U1)7oPYGS?ppSVyPMK_P5 z5Nrgh;%?ic7X9F72cB24uzy?b`JV_XNrJd`*xE=R)L2HoPj{2R|^?IC?27vhg~Yp#Js%E9*~_GFIZB$ zTo3Ng7m90LY;c6W(a@YNhiGYcBp|@oTFkE=;FhneFKRVOq0ZGU3&BB62iN97ECd0= zuq_z#FlX|$H1Q!92p6-X&E8tSggrkw%YYUvXwIz#XFF>U`l}e*WkpvQq_T` z>vmJj&CUD-x1Vf4v}Q%x2>Y)n0V15l7d@X?yb@D+IArVo zL3|=7@$nW0TG&3I6w7$!TqzA@kOt1f%n-dks$~jg(bcKbu3=R|xT>a3ZqETV>hp_d zTeiC9Pt?9I)JrAO?-Vp7@v{I22^>A~6h%6MNR+b0aGO(=I^N&-DCp{pdxQ>FiC`~> zs){6R_RG~tqfuFn_{ZW?#n=Y$_DU?VwDn-R7acr;k#1co&0SuE1$uCjtKzroyVC zbzodMrfL!Qf<|uWIckhhcrZcILy1vz~AD>NX+$cq{J`|MHJO4cUz7OL^4MC_nc8JXdxJphkF`!>$xlngxp)n< zn})tc`?LIgzW_Z?pH$Cf{97qUfP|x7tnNCKNp?+LfZo|_qxEM&Ry|iDw(Q<3g&wMn zw38BLhY!fnNSg-Yh1lp(JKaqSrw+{A9zHnH=kXs!o;+$0q3+S3h~(CO1=0fCh?0GW zw-%Vf;hG>`qaRArBxVt4DIjgJ-ceS`q@o;QW}aZuB0mLzPxNNjB+xK7;JjWc=%`( zLN;G}9+CJ6pzhB4!z9q~?nhinxB$O*6g)B$llGt`8>RS4oM-hHv zf?LQ4QletAa1J($(H`HM%CNqzJ7(^7{7$X1uZOjWW#JlQ#%}(bU7Uu0xU(*C&K{!x zL-JFmsENLbq*yNx^E>xW;1@k3e3lcW1LhLOjJBWgLJDP&mmi)rZmV8FI!4aMzDIKC|D6gnz!nF5I_zC+H%4dKX8~y^45G+F6Ko1L)z5( z{NdsI&S%eJ$rUONb*pU!?ER)b$Qu!8`GxerWAreVqr%a^r<>{de!KEJ6(Ui8#Fx%~ zWH?DDWE4@>bkP-|{;=>H=R3tZlP98m!tuXKhc{A3}s=OdL7l!!7 z7dEZkGFT{Jh<0|PPDj8y^((g5f){eissKCiMa$ebgc`k>Bq1n!c`~j%RU@(K^r4^1 zM-vahG*A}x%{T9&A9+75v7;e-m0*;MEg0d&eyY!DRrlO@I{c&J7l>s^Y>GWO4SeuR zTPdH%bg+$>0os}c*4OV)=#9a2Dpf++Jo2WjXo;G@raRb?2>vywW|ca!$m6H-87fla*?RANFIQn9 z%NyRYTr#C)bU>1v7m6V25wNq~j;{HwO8{Yms!X>}kj<2Jn_C*kzZJPy;b<ZcjQHt0SqnV~IS9XV$!oTLzUxlBs-5&=mQy; z(-@t}hX+1+3sAELjWLd$rX0|m;$e1&mq|gR@3FGte0PMof&~;7mJ$+OOx}o$sfvbr z{+o}_ApAq9*+6)Bdym7^WGfXwDurLD-7*NfBKROo2LFQwOrecmCEmAehisGDOd{7^ z2#&+n6srWolT%qc>>ijYB)PiLlhq#-r`%ANpQfb)JrVruY^1Sy0l3$~d%-LZ#0<5+ zMBsSdMP6sDQ$al57w8DTNA)A50(pCJhEO_k zdu6V?;8pdC@OInVmnMVho^46Bo)KttkLC7@&W~|0ND=E%BOsOST(^B0a|Vbr!tJUr zEj&0MZ$18Gks7@i!;hoWE>5S=9Z5+(-0pv{aCc_h+elp^)u#}~ zaM}JmmB7_0XXkX$qy;M6Qf8-@NBeWWd`;FBiykh~(NnF8Wj%uCzHwL2_KKGAf-k=h z`irTk$9klt_7jdT19N=Fv57p{{;Hu*)9^fQj9^P1 zE)Xj}n!+TEbAmLyAL8k2`5>iGWN2NeP0H=CbsLJ0@p?s(5Lw8XrazJi0}EwMr>J5@ zbq4io$9%4~D0!Ce*MQoN-F49^rTN9~3hDOhulrB?x{J>1y7nmr#^FU5dvU0USe71? z#_J4$;;X8eaht6Ot!W^UqBRuX*nrnb1W?61;XbggG6WnXX8?Dmi(vhubLx?PanU{lc6le&n>PXTMGNExuianG0 zY8<#!_faFSy>gsDdbq)<_&c;xB>6cK8egL7=Zbg3bY8diqqH`JQaE)hpV7Mh@+^R* zuP`(Nk8SL0V+%~J`15kxZ5*Z-I7-lICJuqu4}Dbrjccvw-sEfON--C_(izT4>$mjJ zO!EM%m1#QkGYr#Vw8`rJi=m_a)74#@gvndURZLUjuiP<5(pu7IBFrW)NBW4_r2Vr9 zdS(tr&t8)D`Uhre%jn#K_GfYYEa+SY{bU+#4Z=-70|t2z;DQ`!Qw2>^#@#klIXw>3 zN*Lo-9NPKehjl25+pNEpKFotUkEw5;JDgFXAKe5Q%29bTootRY=L^6My5w)LIXf@NZR1 z=<)r;0ddM~n_kc-ZbUbR(AC$!(?U{M#~r`u;-lN#hCHoNVBaWmaws-VKphyr=x=qI z1s*nY%$BTH>Zgz6&kvdJs=OMFPZ$yz*>l+H>b^gddYFtDj3cNcv?MN^klEl;2EeA? zi5c^Yp;=sa-|ZY z@o7APGhUWtNZMUDHlj-=Y!u(6jVyv%mBJ0f$w!R6?PMSRr8*}y+HVGHIQDspXYU%h z@7B+GCFXcGX$Ns^C&UWgfj7)M$RR8?^a_FhTAxILfTaO`_$kBXw|a+rV?bKy>ckmgU`eu1NN)R0Uc zQLmAS|4&+rAA<6dn0?+9C7(ZE@=myNYISsgL-2$@>X(9nc|?cVe#|Wgfp}yy1Xi{< z3DYvqOl}-YEDP*HCG8zI`l^z1$=Y-d{X&gj7DZUodv>Ny zTOoOb1aBFOc-0x>Y9b9-d4kpVC#8;(J5X&$4bn+Fb^Ljnm}xofyr8*%qH|@~rWMBy z4L7=nL0Fj-Ji{nk!}^XJh5qtCh6buc_oM;%Cwo=FwwzTsJ?{JpA1Ku0fVZdA-)Aho=Tv zPvG|MkLrG|Kvg!|T_7!#Z{tz|emtI%U4>g)D?ij5;mKB(+SPIpEn(x4C_H(Ck)*o< zg3(vj*9b@Kc&N*VV_M5`{3Iw6b2x~^!BVRU!`SPp#mlAuQ*mUb(jmPgimY$9L&hQY zGE3c0yt14C1_=Bm_B-SR8QI@AM1XX-;4Ojn2U?{vS#4wpj4(99QK}L`j}hw7R8q6X zBR-1{dWA}-$CqClho<33#*~pPtxrvAr+tGv8Z;jC8|ljx@0SC8K0~`$vj5&bo>{YQ zuFc0o5M;QIam(LG!ZIWfgdpIKW5JpPZ<$vz5Z|fPyQ$>puGsa7KHCMWaok!V_=J&# zz==)f76&!ZLt>`jw#y1$C{W%_Z$e-1L}#1|rvh;rq3sj?_$N~WY1H}5(iD?TwyA0N zz5$;To_O;gf?X^?oIM0j3x++esS_PZ7rHkk9Z8?+C7HAzX%u~iMI{XJYTZVpVaDrE zigI8ts#=(xkR};ZyPhctti*0}f6P>d4WY}l>9~leh^}jtVZew2D{F^6Cy%3CuwW{< zpL@S=`5>4Eh*CrtW@Uxf#_2DL-{p;LXW^k91*lo!!Dq|jxV6!|&DhuDW)e}d1dd?g zy}9l7F+Pwj(?jkgr1lw|v4;laN>6_?ZSP;HIrG8P84ENx6a+J*M`M_-2+A)h7L1NB!F(JmO3iJi%~dPb7W?nZbsibdQ-x2Qo~!oZE=XE;#&)I zM<35h9K^r*G-zyp%K}A$4v$ZaO^nc=#UkTjr9iFLHD@mVe#(lAwKa^XH@YsgZ4qiJ zZ?9Jv3aZcYQf@ka=lAsS(4Iaa081cD^R?a|| zD+y6RTl9erHz&p(uRqR4WPZ^erpt5YhK2=ZEies%luQms&8nvvB11h{h-o?f{_A=E zG(U9yuJ)vQF+(>Qx0ENIm8PdEx~;xa%U^LiOEhNnx3-3@OwD_Z_g(_25W`Ngl)p7l zbGU&t9jzxmHn}zwrX?#3o(tyffZ21hH547jlGi03Rz{?8&T!Hl?_*%~FVSA9B|>T0 z!eFFT#NfAZaelkC-PZ<}KtBT3wIoDdD%do^F#%}e z6xMVE0p}~Rw)Bk;nt@}9sX2ufqXPLm{TZj@-&6oBc}wvQ)b753f* zjCd06hI}iXu>LIg;`7@hI9gx(JYw-<$goOZ7w5NXFK$bTqkRtxOufO|w2Ovh^!l-N zp0NAD%DFy)r>D0L)so{Mf3{A93_q-^2e&O<#B(nMHek&0>c6$BMlFH7ofl=k{sqCKJO!2-AL_9k9PBZo!QxL`Kssd9REg>1jp z4xesS+@CHZrhQR1&1cO_FeWZU@4J-1Y&9;y!u}`q9UdqWw62R9$I#s_|XbsZ7??EFCOZzm=@|P^Yi-Y{y{-Gz!zWojBOU zLjVl9ZAjMN=i9uM0rUGF5uey0nuRHF1Q)%dUR-t#tjt5wmE7%CK-;pV7JJl-+1i+u6S=-iyslDT-;qMX<<3Z9cHMtY5n7{|*PC>r-uSMO6NOnjW)1{%K z#{2Jh=z??X3gY~jhMoxA(cGONY+fR?v}WxAq91E?8|pAiS8 zQ$lbn4l}@}bnb7n=hk`mpU;qux(7!hMgqf0Lf0G`-0Gi*-g9K13CBay!=*VVf@LUK zAd5h@RxkS>R=w6y*ZMf1YRr#*zQ2w^OIQh*?+k@U>E|ja@ao~#h1+xtw0M+?lO5VC zH1M8y?B=nY(Y}s_Zda7H(~uh@hD-i^2fyovbf&~Rp{|__(8H<3Sa&{#T_m%aA=v5( z>PskNO7@`N2;^N-B$3X!_A&32e}QT~+_baSvbV-^%CK;9jlVy0IzdhbG|=@V$GX>8 z(HY*N_Xg}Num$e&zNEUEWG>-fow^0r%s8Q*L+4LtmqMcW`@P;62*@IFMnNU!r9!9X&XZ*DWVEA(&5K zMUOyoL6|xvl3cb-!XvZiYE2Hl(yj*3@PoB0s(44W=<%R6%N%t6S>~g7j+kT1VAaMc zpi&E5AE@03O9(6Qskr3^nqgq?)uQAuuA6EOwXsq&!Vv0(JaCDfpx--GU$xkMvxuT? zU)N8w`vppTxVmfr+LF>H%UoGEHr|@0np?H{(mx=UP#)F6DvcHS9e)yJe?MWIr)uxi zDn_C?l3t^xYpVI~a|zI>nQapNTC{l*gm&3Zd%yS0 zI~kj#!=UELqI8hUV!1z~O6?axMvT#>Yr6UIn+a;GGo7t_QL4QZk4<7ajuy)+O45(# zpig~(1qp550HMsR58}h}wvOnq@E7+;nwph#VY>1aKvdUVF zs9N3NcibA^kj+sXzGd2W%3riK=RgQ=8j`8w#H|$lulgTYfD4Rv$#xmq@7DRmgpPn~ z&2`t&$+n}@fJ;{SkI!G-b7_KZym8ap99)G@lJ$0&L#U-XBS; z+~QXz(P)z}wSRH~4GXdSj62p`t632BB|rJop3QwwWDRc&7hP5-b9S=$aqg>P(~c=m zXY;w2Ka^Y+K&W%xg=J7p9YN{eq9TEW%CiGBzBn&atV*OGwh$mf1dfs{00k4)9^eSZ zlW^~*sW~k`&Dfhf_Zhl*h35f_?}egXPK3hFP6G`V3mZ1`=tx*{ zXe6M`&nWc*mWBBHYF{0+G6AvZ2XO~6FkDE@B~S_yOU$FpklXtTZE}vx-fX{M*NWdb z<|)t?q0ZH_GES-UUfI%q2wC(QE5lsOu=xr3s6%d2m67k}JL3$G!PVAt6qEPHThS*zV4feXRQ$%lL&iin@bPFK+ z?L-9H_kmRp!@yw?F5Or2@Uy48UBlDE-zx|2enp=fQqy+0?aG(&^}384m^`EIe2o_} zM{rp6+5G;zJHR6))CLumjWq_^jH*K{Ece=yy`;vuGW?S$N&NT>Y%)Up^U|T-TuXv! zED8P1#a^a=Vz4Bu)JRQtVsQxWK+ha_#4HtedE}_xbmHvYU;$|6OlNV8`<(^xV|!Y0kG9Xy-v4htG4nqJG(87LAyYkj zLdJin!2f08asJ;eJQXQLF%gx2_lf0=Oq~A7|Nfg#%=lNI`|m#SKWqM_vHc6hWBRM` z{Vx=cm6iS9ePWisXaAUuw4Rj_A>e;E^1thN|K$_2{5wzlFXvcL(8iTegO2eZFdj2I zA=_UZkAv}l!xJ018d&OC0qmS?9E}Y1Edka}R{BQv4rV6S06nX}N}hwBwc$To{}ayB zvp2G~G%|Js*#4vR&&t1RYGiNbU;(hTbaDU~*jQQV0ZiR&O^vMoQ?3IzSn4^L0^E)4 zZ2&gbMu2~y$d0D=Mn(W*8z*~!v6-_Gz`@KF;9%tZw~vvTiK!#N+U)Oz1~!&9)_<$5 z%>G%jG;(kN7}+`LSprP#jr9Hw3(#`}{QNIrSr{M!5dEtxivuJ8k^m`y^j~jT79jW6 zTvqrGby*pp0#F60{k50%?ez>Sj2!=CD*svj=VbmjD6uVV8 z?d0p~l`e(EIN1aQj%}*~W&70j7UnU6XQ_=z! z3S5}N#odfiS>Ho!^)*3x-zLhWR#KNhk#OJ187(W{Aya54FVzsAFDAy6-{g9x`X&~a zzzo3YeKX^$oZs-!FSkC!Oq)Igqu=nT-_1yWJ;m#9oYwE8g73p0-`!is-!ODX`c`x% zruQyDU!4X(J}HrTbUWACz#~9kYAj2^(ck<8LO8G%G2aQxK8?zdU)-DDps9uRyW34r zYw4dw!G6)Z+k&tZjIb`bVg5n&wVXW*GjBH2Ut}tctiW9A8Y>{*_V3kAAf{MYm|qdn zgByJ-V^0J>RKF`h*3v(gVZP=bt3OVI1`@&1f=a*HVV`t@VSFHa)du^&Y^=Wvu+{!% z?{j;B6c!zs!rS>hJ~9NHYqY2P;qm=NJ}^3PckhF8ry~&gmsDhRbZ)SPH2tp3@VnJn z{EoTimudS37hYIenL5asm2+lmV14Db`c}A!Sz8&Ly#~4^9U(}CntopyeXyZg>a3N@EAFTmEbnKaH}$KT-Du-TF0%|iu3pu; znt$67{&wP+i_nvrO#tbb7=9NMTvhSy5ZfA+_QDjXR)NX!F2+A}Y9y?OuNoZ6b#CF# zD=k#HLkQzv9KCq?JPVtP8EEW5jCz>G?;Yl7BtrkhkVkwj?hvpetTKCgl4&ubTW4a2Vq zyppQN+8fndP_qh3gTKB;r1#Z^tX@C5M%d3?WIEaWl^U+}X#bP5))nteHMk))?p`ih zLNxgN#Kd@4{zuNVq~ za4`KgiTy&Wd%wKgGU`S~UeXVQTdzToX^$C|K6;X|`S_UTka7}QIqpqB^oBj`R>q5q zt|V458n2*Rl(%y^3;}z=>?v~5u$a68jw^uZ;IWa4=8WILxyc?|+-%VPjH&*=g{zUj zwl;&DX3~^Ba%hNi3g=REN!MV*llHkzN@y~iH(m-xmJ8_bF$;&HBK58-4Q^pp;~ZS% zL8P?r9ArRYg$Dhxjp~e=5^!g#Zs}kjHv-2U^v#$b$Key?(H5l@Ha)1p(h8m?+6&0q zSDq;sQVu@=)0Uql)Oym)F*qHPv6M$3w%TFn8#P?QH||7Urp#806~qwONd5+{<|P$d zh@|oOZha}*{G8=kNOUU2HdK3Vd=567=g{BGR>j8AhUa`q%lqj5?B-gF#ym+9i8FDg1hFd0C~>v?$eb6nSwsA{Jix}0b0C@x=mDtsZfvEp2ZmVhaJ{F znhP4sDRo&Bv1JXx3W1>U-xZ2xmprd)p{jv55LT?o4O$-H8NCIwDnvRUspJTwg5jDG z{Zt^ah+DJYcnwVfbMvn?Mdp#_O>x(JwC0wQxX{5f)H}4=#9ct+0X`8Z&;A}1X~K^o z24$A=1R1(_reg-`o=%lUI%X1C^bA8v90ke0F#&S;8&Rt(tYn{c)q6``+ZCf8`RGy* zT;I8p96ZFSV9+nu6boDEUS_jMzNvRgiQ<{bJnRmwlD!2o*UmcvT29Jxg?!~_EoVgZ z7SU9Y*c;XCMW~~?R3ZaxXm$uhAv2!j%FZnsf*rz1LV^CEq$?}6Y6G)mAX>KJI&-F0 zCz#JpXtGqjILjZZZ_|tb|9I@}$I?lSH)-GvYyRRE7r6;;kKjJ5J30oeXgL@5}R z>^x|=1Z0^ZV|QxR`WVW@!&#!FO-@0ElOwyguB_MbCN7frp>1Eqa0r4UdU>GKCe^EFO7X z@S`K5hmn4uJemg4M$OJF&JFS*$xROcAu%!qBQ+4l^RedD!-QzEO$^wwW!KY-YO z#k%-c7nLlUvz|l3#X(;Kt6?6Nn+sIH5Dtp&nG!?r&`+!9#=IlWFcyQErN_4QL}EUd z)*0hVCDS1wIC5#Jt3eT|JmCej(=e&qQ9lp!H>wJL(1^kh3{wtQ{5p|o9x>DeIWlv@ zP5%y!o*~mL&pCxO(T=Z3Ixju1Tr4i4ef;@;X!O0w&xA~GA4#VwblQT}yJU4_y<;!h z{g>JGf2wUX)mV!g$$TETIkoVulyoHw0}qO)>a0W{h4JLX5$<4SA-1XFDcc5b)23xH z4f7K?Zd2Jh-kE->U7tj3OdT@sk?`7;D$-7p-T;%_wZa#;XpR#F0e%n8yYRfuo``AqfDE#u)2yO^A5%q8jxY;G zY%za983~6byB?@lS6|+6Q(GrfF1CH<*RSIpiIE?bWIgYaQ~A zw1;?|qq1ygeIMCQt@56BTC{v=w_bF3{Od9U%sg{lSqxFX!>sx&@!p}q=$gs>;4+v& z_mSd`up3s6aX`kKo4A^P5YqM@5sE9USKPlu3pHQ&HD_{{m7RNH7xOdKxA(JnIm_Jw zyxcF1Q-rn5b}EVdtVH!l^0afoVSr;L@GR#8J}q|U=|bvqxb&>wW3mp9Y6X=hZ{4r| z!W786G48sOxPUw`;|sR_O4HGn?<%US99y9PRprYWowDp<%)}ot6xyI|PkX!L-gJ>$ zh!|Yl?t6+N2C*E!ehs<|9h<)j7kqf@Sryq}O9^6SP0xdbE+Lq{r>~%ZmwImZLchPb z50T*zjxYk#)IXA=nPy2MV|hQVu;n9%;C4nk4fo}G)!|{ugcgcmv}Vd@24+uRx^su~ zaVEi4Zx8p`{X24R7&aQ}Rl{5xg^0O6p`!i!3(vgxJW#rse<1VC*8IT=Q+zVV3-UJy z(}CmC5K;9C#DUD>D9l7k7}@~L;gHh<>L)nDk*DtI$?WxBEpv1gQw=}5a#HGGeTYOr z%MgN)U<5XDVtyb`oNdHW?AQsuOlLhq>!zXop{RJnC>K$NM3_}^jaDi={71=I%sX9E3)FVaFIF_F1gL6w9DNrQW$Q zj^J3Z@6)ljcxOl21qdmt(S^s)Flr1KQJG~`&s&YBMb9{oY=O-Hb`n{;ku7Bge>IP( zr#hZM8{YRLY9aLAm#AX;2QX32vC_W=Z8XEoTcg*2Kx4MA@S&j7H{qVy-XeNM5yOfk z>k&DiIAvI@(YYI4#t_Z1+D5f9sQ>8>h`D483>0BAMV`;ne@?=-E#x4-OZtj71XJk05)6M( z9Z*@_#~?)Qn+Z`lutpkrGf;A!*oGy(z#Lm%BF#lB@BH!jj-Io$qvX4=wW)t2q^qe9}TGr|1O*>GSpc8*kUD-zcH+ef-4ET86Q2t)p zU2`FhY1 z`VDX`vWXM8yr~Y%oLl@-@KtXx-w$MvZ}B^{c8uC1*kv$k2=KPTT1CBLRRgGt6I z5lWNxSNkMfCX-N(CI=!{Il7U{zRGGwK>;F)d?0b9p~8R~cb~EXjo?o!7FeE9csvL4 z-=;B#kC$4aH9R|E#`)I#fY^9sFZJs8ijhzuT{3lZIICj)QuC4Ul;DS*;i>MkBffOA z^?-8e9ElT=Y6?3oFzO$AMqo@#oTWHXoVsZixxBlIo;Ksi_0DYHNg?gnW}a7@I%F-- zoGY#9f)}q_&j)%%1laUT!)pp{| z^-Ud&-5|SmOU>7!DE&bmh8$XRkc0ahS=AFq2u}geregbb)K?NSxP`?@~<6YpQLBPyPmc< z5^oG|uXVF`hDE%k||)DqhJoX?^JDOx=e1h-2AI9w51~pM%JDMAK|Zq z_83>w8r}dtoJ+R~;C&cdu@#Q}4g)?uheAnOm>x|pf@VX@io$fg>rVo?%fxv5H^!TzE9@b)ctuNE?gkoz?SO*aw`oxL=A^@j?#EL8|;J4Koo@0_@loxPJu(zrTibzlF< zK|{F1XBM$8iS$4_zuvcgY7xr&-J2_4?IJRRgmyy|Vsv~DT~xr!%fUc~ZE++8ggEbJ zp0szOmE%~MVR@wMsvEQW+a_etU34OK5XjpGM~>@d^Uv3_I^I;H_XL^B!a1glQ`n7i z(^gS6$vpgel3Z*Dm8dm#Tj8+HB)8Kh1t?4!spSiEa)x2m)x>4d(^XAmAcP!ib_O?L zV)jAwufUt(`L4I_$PFFt5o1;U){ggxOgALH+ro#sG8^ZHkogfZbdhaJltO#wMLk$* zqJm-u|0GHj_>|I8pXVwuP4d5Krch?&onb;mS)136#|zOImD--%3I|7pWT`a4sr)G& zFl5+Az$&RMkl;2zZpQe{HLF(?XKRUz4YyF3lZ{cp-NXT5jXzhfqrCDG!sOcVoPsSN zc(M5ca)QlklXnl62^SVUCDAdfn1?#7`vc@V@9_PZ8U%6c7s0p?-}D%1y5ki5oCYsi zvgmylJZqNqeLvtFW3dC=eGp3VZwO&4P6|bzR@hKH4Rbt~BCQZ?Uw4Dab?7{N%rSCLVP>a*1PrPpaUb1kq)hI-Uz(qa5y-^8$_35aTD@BYEQ$k|%L2kgT| z$YtCRuP?UWoK=fpBwLhB8`ttW6P)oBn8yj}F3i{QL_O_6YL#mhwdKE^G08=Rl_KYD zp)SKnZ&>K2S`N?XFpg6f!V?@f#<4u&7~wCQe)^`y@{ofSeRBiXI`SN;+exf25NMj3 z4s<)tH(!bw)6?*qujp?|H<(G_>!DIr(vv!vM39I*St*3$ZJeu`!(G{3QI~Pu5mW1M z3YmktCUSNsYEcYY)GYqIp5HIl+*3&F&o*ywg^UKc7gGbjM0*EetHa{dkXM`|gzf^F zuvdfA4R@$EDGx6W1>-fAs(8H*8Jitz!E)T%EM}VP>kV?%adN6u?BiNF2g~l>3(RG^ z2#3XeK*-T*^->@izxUJ9##FXCm?JvexukSxr6x!KGs9|F(IgxlD|r*M^(PoEXD5^0 zT=NnK@Vm&^*ujXbkI?CnthH+Dmm|4|YWU%tY7iwFa@?Uk2K#)=9r-I>^hbdPQf{@J z_!wP9_a60RMqN%3>lbT^qYg2})kBo7C?Xz7h&etF(R|OWOHBMHzWY!7OzluY09fn=AyIG1`Nw8fIbbMhFR&H68rPYPqOW z%N1DI6X+&fE2^+5g7c6d(#AOy5a}m(^`d&1c9MV*m~W~B-v%r_=jG7zoKTmL_LwE{lErK zS&@ZT&oc9pP+7RI?1#eGg~149SlXeqtGC(qFqRbB@LB3!pamXP$RG_)Dj)0`??ric zy<`n-<1fc~b~u>CeB0-N$uwk;ebhz;a+7vbSq1Mrnj6It$-9d|Pv(dI%^5mGSgVt1 z>jeKeUYMyjwNypcSaU&!AbGso`BHKIA#?b?%X!1uoFtTBULCxupBaTp9e$TrOFi-5 zw}cG~)5OysrRa?pfpWn66+e@DkSjx#SV*{RXeSv68>kOqtYkgu&)^;}iXX z;i@(chbAfZgK|NJ?D86a@Fj$6TDHxZD+1ES&lRc+QNLJ*dY0u{PPr&xAhO``vU5uzZ~vc8 zVxDhldcVSQJKm+7F?pLo?UiyTbVrt!6(zCc+Q-9li~a*ud=PW;el=aO;ZjG)}}_=EHZBgKujesB%; zSDI$@Eg@=k)#KqPS%AB?KZ;cJ_~FEk+Tbi)NUpe~w0B^ub%Y@K){3(E8~WS*o#LtI zwJ29i@xlbcZpO39B_f4i*F?6`Uq=6?8!*+^Y|>yph@m2nJG}D{{6F|iQ z7-ujh8isbnmmJJwhX~Fkwmm9q=0CtL>T@#x71>FvcN;0>jY7PQuO)94Fqh<6%Ow7W z0!q|Yhz#SnYA3UG;U45@uxbPWJvP`F;PHWl_Oj>$uU8ybH$kuk!r~R3=uGq`>5xm#b_go`B zfpqaU$%hjgp!9d5`M@rp#+-Q%Ts3!pBi=&fsY#9&@8icw4X;PynkK4m)V;1KA@ms9 ziA!w0J8IpQ2N;(~@n4L&S_YG3F9lkrEFLCh*#m`bzYsAVu=L;{w4X%S*r16#F0Y=A zb2e%BZ}3!m$8l~v^VQ)<79*@vA2#KK6=wQPO<;Z6NcVX_;9!`0S>$j^VM`Cu$f8f4 zYcedXR%d-705_Xh!22oF?=}229325ozV((y{Hv=2HcwW+^a|Ks`;^fHq^v;#1@JmU z4FhQk4w=Np%OJm}Xx{MVQQv^yfl&+k;_QbuD-l_ZLrd1(tJgNGxST#2EvTXybCLtb zF`=F#-VVJ~NHKb=Ej-=THxh#L60g{QgThTjZMx>J0et!XS`w6=89!q(qBy@)8gin6 zTe63)b6?I>b6{IAOJ4krX&e?kcBxBVk)|K4wTmmfAei4Jx_FzncX7t*$(V9?gd91_ z>;CjnKl)q}4jx0x!Jybs#@%NaBXcO(C^9= z?hM~W!S`Mzn3Lc=9@Xa5zJmwQbgs|13)$Mpc^&GW3=&py=qipHL?MNyF!Eoqw=mzo z0ViG3$dr`}sw6W!jP_du+oYCpyQ5XsxA{muJbh_kr zLL&=9BVLo>9+>2t1kGPaBGxu@N#VnSf8)|?nZE)fQ-m~Ke|cvv$lc^8I%7@IaNv+& zS*l)4;Zc$g-u>KtLw`}{#8CScu(6)qnCGsbJ}v?cn}_djGI_zj8%}Y(`^&ZR);y8{ z+p8qkOd&UlU(g97utiO|LxD0efaBjdc636F`_yLv`%1kD2NVBow}e_ietfU3Cv^ zGAWAT|2%5#uk=-me2$UP*k=uGpYG65mFXHgH)XJNig~v3GuelyyC36aArt*2O}CC0 zn%|HcxFjPH{QK!MAVXCR%aD#lC#-vbL9GydysMZ`L`*%c`JWg?=P(lihKb z2Q7%sIHDlk6|}$mxST^ou?xeQUVwWB9SvXu4O+33(w)>Yk)_V9eNFi%)8NFKHT-DC zjO!tI3@+F#ZqQEwj4)FvhA1k58HcqyT~huU`u9XW^{rjZz-JkjKQ4ppTd_Aq6?1zO1oh=Xw@)#0+1 z%d#MpnZZ(=FRl67+FOqG1(_I&H~A}Ub@%U*Vu@7mNBxZ7M1Y=Tcl!=Ae0q1H#JTpy zoT$ySnSLDAHN0F!n2bJZ^(8u&w?wDKz2vKOeiWR;M>jO3FW8hXU+m1<*)}XUdt24c zn;lQ0zE(8`uN+E4oKC!JrK?$8NyBZCt>0*HChX)X7_e!Lap;uW;|PCAmMy8J{2ulA z!FpJ}0Ef44w=UG;ZHyojm}DBfh?u|NmU%6P!Law(295K3$cSW4(~K>%Ngy~l0Rgqz zSRvg$tnU2h{u8nT%BiWW=xQ>Ii0KO}R6hUs)rz7VTb+L9FcjRa*nZV@oBoLlRYtFq zGs1em3zi|LB#S%0Pbwx!R`lGdhBxic-5;NfN&V{wv6zf$f;$2mv8J+`h03B_TJeXz ztix+Ke*jz&lYM1db+t*Wn{Ab0WGNk-6(b6esOE`ddU+Yg{nYDe%|~+bf%y*-QW!2v z2#PmKBSVhy*S$-LHol!>t$TDnnW2Ml5^!?Huwzy zLTnLRGMiKDe5L=3xpxi{r0E)b+qUhVwr$()p0+W~X?xnXZQHhO+qQjsp7(oqzuoxa z-n|?9$5ur~Wo6bmd9o_&L{wJQ?>KYuI;iSa{piy>OY@)?fTwW@X;>WsJ4@7L%Q}xG zPA#koO(aOltQBU9RL5nW{bGF*!N;hP2aiAt^&&|ivZRP2yM)xO%qvpUYVqp!+C z{NpL7sVFNMif3Z~V;m6q#UG4QD+rF3W(om54qZm3PHxV6A&Yvg2or{u9_b@D&WT!G zg0`{{Jw&eLB^<~R{m05Kfax9__5id%4Em4i6uZQofZeayPmzp8$Aj*U2U*SfIzHJ?w^Y4lx#| z%A7D7mBt-fFj2B2$22Lo`!}t>;4|T)5uuaXeA9HmdU|S;jpP`C{X)KYgcwX)Emshv!iw7L|IE}yVOm%}JUxZe|Tf0@oNN|fc|ifM&M z3zx`CNu^$1}94z60p|oMs7+TNow;9)hop+`=HmEaZ~y_TIEKT0vx0YGnZfmGiG&+0EbBA zE9n({vX`FFtHp(YEqO!r;8+S-g~l^K-~Ka)8nffsi0@+o$7!ly73&a3j9)YCV;LO4 zhe9yzf0^VyvhAZV*zPWl^kkB#PP>+f7`Sw`X_WReP7ffeSkeCsX6SX_NV>GCdHZo! zIeq1^7bu`QyH|He!Tc5rhvJVBEaY6zx-AO3u0%V{;-f|s_IvBgr_E!rz9fPz+pKyA z>q1veazommG<}#`7neG5QNzd|5;yol^`|ad=A!h&Gs3%;>`JiH_7xD8mubb^ep-5x z*PRl?NjTb;mMmkJyxGK%2^rjIwlC<_oex7IAW8Eluh@>(_9+V4P3>|eqXkyTp~ur$o{*cpaFaAtau`FC!OY_YP@yl1_ttOvFJGt(}7IHYmTVKNg0gLa>ra zQiukf8)KV6$ME{$-cD7xtKlI$ghV!b%VxE_71(o7{5Tj7aoJpqSYCyRC%X$|JfF? zh)-2v)^0oyqI^?ngtK7(3ArD%9L(n9B04AO$E^j8UMxp`kh0y!=zVZABZ-EyRxbL(Q5Tth)^>hrk;)R-NQ zMSrMw0a8;Y!RX;6Ok>vi!I)`hLU%&(PaiHTe!Bua#z|zuY`=4hikdshYRZSkRoD`2 z{}27-Ldz=b9P@aBv6XlN;CKn3FxSL%dE(HH6gY??R9=a&{)0nx{;QV+f+i1aO%v^I z@o1JBwR#oVC<@~0kYfjFXE#U7#H1`XAzX2QRo--Vb&laH7<{48d&3;->7IyF5gR%` z`#_OAbN4KUi$;`RdB521mX0R-jaxNz^3_lOlyeQ~;2A|H)U{ER3~rWnqDS@Ik5gio z$c{z6VonHn;U}UGfv0heR-U^08akY%@U z*nUWxxYW&I_>{QXuC=(gs_}GSYgbQxW9)XGx@u}KFwLzR{&t?hh4&?E2n2#2V{)>0 zuzLFhqHSYkqEZn{uOC)cTHaxjl)j>3=NF5Zujwd*R^MC9ICm%Of??PNj+V@Lxw$BI zMD>7{@4DN`uIV7}WfJymOtO-Y)jgw?{TTZ>BnTQb9}b83WE|o|OZleqk=YhK#C3&b zYHiu%7mn=&?C$cHeh$>&@P=EU|CdH9IF;trDyE>&3C>YtI0?_>a1pWzBxj_ZkXihX zJpA#{8M5RLL5?IPDkL@aIgwE;B~XJBiigd?6Ev>4Y%$H53+{FfJ4J^ogYk-al2;8p z_#3bk+MJTd%Y7-6{IYhtjm{zc1z_0PIzJDsj}U>fou7sBx!b-5fO1^!uo<>ppJjT% zrkH4khHB{Wq>O9pUzaCm;~tnwr^CK$vhdO&L+I-!bmnaQ4Wu5Ik`zOSN<`WfPAIQI z@#VG~7+%&!hdn*1wUjqTg%uJAnS2)Gor4J}FEdL0cWktGdNWz1xPp7LX}9Gh>kL0T z=J^cW0U$FJhU_%=8cz(5>y-x|l1 z&CNeDr0a=j=qADHhZ`zy5*}>kNWav(SFeFf3LN+Hn}j!*>VH5Go|Be=!*99yM;Kks zRgD2&uKSJCzAsANON@AXQ3cRs9mGT_KX&>X1ygB#MbV@}HvW*$5_T80l8BPp5rD># z(Ngk%zAdvDy)`FVcn=W=J`*GmO=mF>@P@KQKv}^5mDOMACfLgo{yy~Vu*K@(m;t0 z%6O2d3o!S)3)WmK;@I#odOGxZ?)!{d&}53~zP46tON#ZywOg`a`E9guKg05m&uNR#*m_8bhY4tJ;;-9eyG{2<%_;# z+TupR!mKq<90G|2gTB9qYh9?9{86&{hhP%uDp?_H zsbM=-f|z&R5|0S(ujQDrgC(P5czzE6Iw2ALf`A*?T}i53GMx}mi7ie0$mc+hejgDT z&@Y;aJs6~S8(b^L_oopux<+*2o~aY}ydg0Adl0-uTsxT4E-jT<88aXQS>@RCP@X{_y?u#(@1Wa1}6Bq%Wo!bNB z;tY`ZlKH;zMb&0f86)64F}J;{^aH}LBcf(8XwiaOI7e~CL&z=y=I7>V#rP`{E#Qq( z_aUvKb@I<5zQp$EpRM&k{jsA0TES}AMH|CV^DB#*Wm-QK;d^a!MQD9FIK-;K;0}l7 z-T<6DbV9OCK;riW#+@6Sd}XOHW8DHoawN#_KnM$WDWikygG$09j$im*w;D8LvTL+) zS4?%zU0bPbXSwxnh4b%kRRw`FfF&jR{={90K8x< z@8cZq>oprycD<9bB#u#^T1UmxC9!F$uCq<5s34y3on-Jq+HWv8FbcjV-iogsGw7o>2|nR*6r)igvq7*DKE2s2A4ugQf>8=AX&m_~Ypu#NRe=$L`(*xb=Y=M+F9 zlmYeWm2vZ>(f6Adwl1Btq;$?1nak9uX)t{l_x|@8GNK13D2P;+&z2uuR_N9BqzX0y zsl8f;wWPnAtRpKiB;M7***~7$3$;IOA)o=PjS3ybjU}BKqZZG#%8(!m9ts4j`S>#L zw>5wd?@yn-G8xKTx_v2fsIq!Ks;vdH)`@@V%$iSBG9@3p!sIMKShErvM|T4RpHUU7 z!+}>5Umrx3`k=&32C&fm5y6vjPAZ`cp!)Lp-R}tJ{?lt^J{8r(BLC8h2<_QqB#7{_ z#8*X<9b99Aul&QF5!UfspVqx2bMZ+e@?$CA5L|IMkiN1Jc&l9bY(!>i?$F5KeAt0oZR8l$_vgh)%`82mc46B8+U}5CJ={ZiIQ$S7WHb%ba7G}9 zu0+lvvX@L+C;M{Zhf%Jm=Enxyr)kB460VWE8SPGmaRG(~ZnxuT-225OTdHE)YbX&V za5Y3uql;hqRx2S?QP>t4*f}Wdl}5Ex{?)Y|eB1+7_U?9x%TAf?`YldgQ!hN3N%ZKt z3`o#CFvS?l;Tr@xNUYcxMuAB}>N@gv;muaJeci3av~CAVs@`Gf5toKg_9_V79|<;l z^V+N>;yXKO^t0pSChbD@Dje=LvBXHTgkzE8b{3E<16UK!RHo-q?fkXNkVrd8Q}l{) zUfdvxB1{6nZAL)igYds8om>d>VUl<2bTRCYTCunW#Jn^0yB#vaKCU=*1ruoT4yHo= zwkGGXxOv#~gT=;aTnIYDqPb;$|706T=F?CCQpmJ~T0eGG*!Y;TxN((q63bIbFW!`J zfBe0f)CKErBPyp}E)m2GoYU(jyXGbh{?@3i^ouIR^wr3MVf6!1(m44?Dp%RCLJ*YN zfPY01ashyqOO_iPO7{x$rSTOYOT1vaE$sq-Y%$5p^ICz%a6ba^{*`zPM0eqkaTz>_ z5iCN-ut8;EGD3$Ib}_$p3l56;G+Iw2)ES)sZ`RS6u~&OYDtN`TaXMSzxJTZL_67^r zHOuOrBkbi|WT%k*v-_ovq1guRPM}2!LNwJLqnSFgGfzRat;Jq#mV#HSI022M@3aUA zLQpbSCw-+spb@|NrZNKG1C5SJSF2Y6ak9<}BvC#_AB_7Jp6*0+`HZhf&-%KCE7m=Hkp@42SQjz4*1-9Q+IkHvIrR`0k;ACHw~ zbaOw?6MY$M@&!zZM$T&oD(z9c&GcWtzaiOUIL(8P>qzhRuf&ws8EK|>y?Vo`sy-zc zYlEqLx6j!GswNgqy|zDN0N3gy!Pgtp5=d73$=YK%cIvTWCY6q8Rl$c zjAMo=Bj8qb1KgAQ`!M&@6BB*omZq-vwHsAi>zn)SY+9{JNUnRPV<2HVLZ}E?mvAs` zL%d2|Ayi?+yygOY;A(uBR+X4%;d>|q9ckR@{p7-f5SP@h^wgA>GU@rI)OAp(*15W1 zx)(IqcZAsHGIF-y8KN7eZjTypUR14J`EcYrj^M`nQMROCCBdw3J$eQ5a?O(N&EO!ccKzXFIGnPF~SnQOrJ zeCos@pREe^Qj!ovl^P#l!C%a*E{%DtY(e!jl}XsfYH^f{7Pv%9WeOTPN1rGQOw!m9 z?m0a`>-6${{l^e^s3tNk&$W7?HONaw zI_m$-VR7d)_?C_s;s^$Ikd#=X`&LFm1dhEt&zC4zj$SpA3U6Fw=)S=~bxKbY}U4{hqI( zkU*u6vQc5h>2WU-nb^|{E4V~WnC~THf%1_SGa6{9>wCns{!tq}e+lYrfJ?5`ds9yD zHC9Dwd`v(cG!`dVo?nb^wd|kp;uLW-b8?9EVgUoM3iBr}TAJ;pxOR!O-nV3P+U(XS z;C5ln9s8GB)YOcZ@EAJupV@pb)3cwsR7b(+1_57_lB0AvaXRsJbGMySNnvU@w;;Sn z73Tgx8m=I7Q8%9BF>7h`_RKGLy z-lobHxFqE(TJ;VuaKtB{tP(JCFALU?$X-`s#|UaDYn&4F(((<`u_AoRVot@_%B1Yk zC(|1(bVRd~ir%0$74KoB3KuERnl#3=72ESlx2ag**zx6aM8iQ4P`JU+=k&G z0x59pH(}iuad|A0AbRrHM(@Rs;z5Vb;$3>Kk4yhZZ9 zUXtE!K{B)qDsw1;CUjDHuB*g}YIwZIBYK*CVvWYB=B==4HoPvrptSzLqO#bx3 z2Qh5PDWziuf2(He8dSvl8vbGDWH}U68LGM_>Nhs@*?GgAto%^i#Zv*h@s<`f7_%hhnZY-mY;2lbrS7<%nw)BGc};2xpBC3E{L zxVpk!9@+vu)XQ~z$)FVhi#f}pcIx`W7FF{qCjPDxjg7`$mNo4VEHX=j?Q9#m`%zKlEt7J@DF|=hcyJMB%Qtz?Xml;4=uc}-$=3_2xyc11ixS0q0 z<(>Zsa}e#N$HZ(!Y^MS9_KoTulXE+<68_j$Fkm7o=2N;`k|zZi9Ro3->f@xzGUt+? zgHx~R8wfo^XG3r-Ukaa+2CVp@hpjAe?2)l-9&(bXk*M4-dxv=h5 z^a3%3nMq|p(X-o>|6;orb<<{RnV5Uiz$#DP1hI!rLNb0Sfppov<=rit?QoCsyQHw) z>$G~g-F)2P+UM9Vo%3rsQ^5CuaQz!~n@QdT3Xib?D9%&VG1)tHzhy--kCwN^@m)$g z6s4?_amlr>d-J}7rD8&^%X-CD(Ny~806KHhvb-$vy|JBeMOi%!uj!n z%j<)Fb>!=C#!W29@0L}m_M=y2lEf>Lzo{`O#pL%B4uc{5M3JNwCNJ#ludP*93?W;t zl!5>3_T!D%^h!PET#|)*oXm%X5O=u1dmwL-$IEV7#q=5Zn1cg1ClS%uXfu_S{8Jdw zpaR5$Yab7ltY1$sFN|q@`i8Jb-twn(eb2$oOq}DuQ1d0yCKsU?{XRv@(!}>1ZT;Iz zF#zyglzZ^)0}$n^DW0yBwr-(_aw&CEkKYRma@(wQdWGRW?TxR3DLj+IHQ!O{SZvx` zM!ywtZj*mGek2;hGC?{V^SnK&iLJaWq`# zFBTY@ij`|%i?OPff}tX%RPkQ|L(ueg1w2U66zt4vX22fbQ>yUH=a0DFGE{w!+lLFk zdw++^KyCFU!oy$W5MV)iRud_jI|(7px`pp_o3=Tzx)N(1@$xDG3FNWeOH(E!$^k?* zhqI+2%q~Z=c}Fv|ggVZ(Pm@Wc&Zp^3y*`MDUa3sV`X!;72tE)lM-{M7cz>H6xmfdNet`BoIds}aBPL|sZ!-Dt*_Pe12Vzms-ss1p+9w&q0MT?f4 z{AyaK43fE{f{}1VE2a#iXsI5a=&UU&`%3aCRli`eNY{n;1YP+UjQ(ym=Ch2S>w3^xW;B4w%Dnw}Uod9?{ zc2Vxi5!eUY-jVoQI6;@ks@DtsP#d8+4Qh+-K7U#>W_D%POCn>~1*A zIr+5ThG9Jgn%o-bqg)}GC5f56FpoL(jn&>+ta#0~Wu7#jSms{RFB)qPQfAqBDA5S@ z#jX7Pc=PB<$gkNJ?~h)c37;LiBRdzeAo@jWxD zK<=M$mCR0)O!Wo@=HtVhfMpw*rZ(K6cwPbTqA` zzpS$Q{C^-0Y}j`*rRhMOXmfNF{D@?XTKSP)T1$I5-KC=cmbH49nSAl}WnkE&ml>2Lf*;2q0b_NO zU=W7-l^i>9qP@g+;}emt34J8vL+hpNL;wL1*ryfolrwCad@ck$gc+ZF+z+74lv&s3eFAU1 z968xVsfHZQ)QWXb2%(C=(bDrLN)>q@Kvb8ss&rCaV+eOsjpYv^;GT_ylEYXKt4jf_ zKN%CDbP?x>g1U;w>n1eYqoMDfkg+v+o9ATGQn!V!Li&D1p4v+1!sNytOJ7TqT3>xT z05AZ9`X+-T*rw8xCn0v6Y#DPfTU^pZw$e-+3>>&cZCCpaN9XqrM-Cm{{cme;u33EB zt}!^O1}zg1R>5coi|{*@x_^+A1`MqP+X4tBLakm}IYtx+8#&5wbM@7n;HSm(NUu6^ zV~K>^{4BMGR$IOPP_m6AcN@Z{9B>_$9TXyYo|){rinWxOB0u^pU0ejAKi>GnTS!k> zkTTVJ^*zY83G8ym+7;*{V~-N_34eqpZCN#Hsl-=6FY%I`L$lPY2MDhA1=e-R5eiE& z5}3do@%Jbm4y}%qJQqAJ91a>L zq8s0=ogUlYbPb)A=utFfgaVCD9KT5>>jhVrnn&q)^eC7mO+E6-e$f+Vi&CIiUm#`OCy2(Z+pe|L!!JT!n>+Mi)!%aR$cg3fy>um* zq&6aQ8=t)z|6WT-`iv7LT--c@8LdJ<#W7f@DJ-r=m<>dA%aaB%qyV6%8llwHaD>dD zfH6BEY{`M$Pi0z;S)CerB68+jEz6P4?J{a9#WueM`aS4UU6zCS968o$ECkQwRNABsaJ_tvP`e3R7gaZMCIhlLH-)%^@`Y)9iEySGX=!vRI#U3t|Lz zdDFBaffi< zY?Way|DrnI7I9M$TEL0~fwMtui%V@mL@w?Mlj30QLnqLQgst)H9D8NmqJov+fku9^ zJ;^DV!OV8Tj-8;dH?R;21`;GH!mK`8_R#F^F&H7G2B)7UR%(QRGB&xbsL|**=D^#6 z9Bu}dvN$a_`A2a2Ft<(6qlR8zFK3RH{HLr@8@hC_+OF^$o!|Gw>Xr`tx}Spg;>4fF z*GqT59DP*Ir+tYq=SQ#in;`7k9D^-4AVloWH&2UpY2?VKK9?48`gU`j0~_M7j9jIN zBLdvzeiM#tDSHzI%l(rEA#8KK>+(I+@XWa+VvqTf$LBQLS@$6c;UZWE9?<)nSq^TX zHxAYDw&v5(v?DODs2lr_jc3f(&*USsoIaGGuJr+d2{&&zW>Merxp3HiOjk=#g_gh_*rjtM` z(-!>uD`E?*qA6ZI0ZEzTkGjyCkP}dNR<&lfHsS*e%8W|qpK*?)srWP^TZahbDGAWm zp;K7ZCMrP{q!@kdhg1iLYE%!CkUEy+_p2zBteq(iBh_cJ3UhfgG9{{fTdnW?CA{O2 zvh+jG?Ci ze#sncS~h2f>)WAeaRb0exgcq1)o|LHqUDN_^u=q<{wF~u2-fb3edSh~Okc~iWV%X% zy1X6HTKjFvUlBRFKh~+J(A$yKARuJ|FjHl~agyb`>A6C0|4@}E{&L&?^kEahGqhOH z6E!XcM~!K5cC^w{y1BHJZC8aqaEABiL#69rhv|I>!H_|NE=+$fy#AgT#W=RAk@3mg z!{eRRPZ)v7`h{-q&NW3r@M%^^XDsZh73;e{$LuQJ#^KX<1vq8##nlmdD+SN%skf}+ zNRdX^L_kY9+I=^WlOhM1K@WfV;PrX)qv{!zIP+(937;P(cbKs`fI);p&z{j3n()cP zn`Pxaq{4$Ly88n@7+Ig&z3e+=ZND}nqXmH-79L_IYD-E3|Exu7R0H0jXqvCaBsloy zv&d#>ttLOXBJD!7^4HSG;C)OhqC#IW-NG>7T+_9wQ?HH7$$i-A;fcxwY7v-Nji z2n59(wCP+blC66)N_Q{5diXjKhG=HTv5Y~`orC%AW#Hs$@r}ia6l|j`q*m(nqOQhz zTuaS>fjXW8s#k6AX6vpFb+m`WsX-at@FFbXTp}vt2SrGYOD5aqnC;{WU*^(}y+Rd0*(~*_kp!o4-OdcO4M^og_dx2_Q zYmj0de%*`nK4AUKqAU5zvUVC<>i9udy`U`~ z@=jGUN3z?-=rT(xrcGcaax$s={$z5O=Qk|>#nZ5`r?YLtxl{q7Ec73oBi@)r+tGZy z0bhUth)|$TObqUt>xBtN*qVnaq?_D18i9=cv}u}rf$zuABx{6dpRslPLT|Vo&Av~; zPceK=6erP*WX01|#=%?%ohIeR{+{kmj;Opyemu9jf4cNScfHTG_sBam=)WVm(;pa2 z%b18!p%Zz24*s~&2r@btP%bOftAuog_luls42zD4jU7J1OHWoJunrrZb_H1b9m`5H zM=@XsZ*_qcX)~_7Gdc!k$rl$-L`_h>F|ufo>5{3S=iZdRmc}oFr}MO>6w*(S!p1rC zdwgtRi{FVJvt47^7Qw>U-@ZT-)XA+73PEwzlg$fmHZHL$wlPFX1hq^?27gqa?AS50 z?1hv@I##+^E|vGsPLgOkdm3Q2+!Y06R*ALvVD#n#=X0MBbp-s(Q4UsVMYoW{*chBVdy+ zeqwVj>nbKXZMi}zk9XU=GE4gpXmR`%3*JLu?V%C~qr9Pgjt}Z^!f(H`wmbj4*tA8a zIF()-m`xa#I2?`8#2HiaN}e%1Emr%qZ12@98~SuY5LGs8FDS8#v$s0T$fy5s@0X*P zrp;_y5azHglTp^`1v#u@XOia!IW*3hlg?lQkUhZFJ&}lw(7Nx| z7yB;s-Aji7RCA=y%doDw%*}Gk5=Rq?B6rws-_O)l8J?v4m2+wjjQzG#J3C@*PCbJ! z!Kj~?lsVRETV3qdeefd~x&f{&;Twr@Tk@Hha!J)rXq4Yia+{O{x^oI!?9Dbcz-j)9 zSH-eaf@+7{eE4|TPdw*S9C{|WQFW{0#vG(Q3yj>;&rPwJ5o~D}paBJbSXqPE(q_l^ zSVV?rK+ccLL061MWMk#3ZTlfbS$_9zr$7#P<#8+!j@B~63j%3ico;e z$2Upu>@JIU5#*V*AbR6=5ZPJu2WhtTl=e^>zs*-{iH5QB4qcv0+(GR5dZ@eJ3@deMm=?u1fxy%`FgR1yj(fh$m$7Oo(8Z^KjO@g2nQf>4~| zulXV>8K{5H{a6yeRwHMq=x2UqmEfZ3RT-Z?)-t%IV>M6+(e9qA*CQG+U+!;NJ9Y+we z`8;?;qtqS}bl$s$?_x=pK@aR-g>idN`L-j&73eTCoSDSPp{DEiL>*%b*u&CG?-nq#)2w^9F_R{Ut!@+|&*Q-Ze4e736X~ap}3t%)X6SqWi z8<2QnfS`6-M;97H7X@rnfw0&*~VWzK%4 z=!q~tyBe($`jJhBq&-v8JE+Uj=po#b8y`TA%wS=mfhN^++h2%q(|_sVGn`;6K~(P& z$Q)E;!eMx9;rik3x8^Dcx?5`>74yV8ZaZ#@3Omte#sp1L$nWj~d7b$XR|`!qDiY8w zC4;($G`K5qb`Yv;UaMt-zE`StN^FRuWo!#89}xN)-j5T(bzE$2{5 z>DR~G30dEi67Ms|xf(dC;izOs5i*Q$t00*!aLE9oL{+fK-d)-j;h4<%&8F~EyZC)Efy& z<^cQCT*;DlK&&y&LNtU4&o+$Vn+E!_pATBfJ{kdE@&YDyomM^ZWAM^&16~3Wi;#=I zj)7}a#lekjYflB!Y88u|5U_n-ruUOTl3)|cN9p*;H|%C)LRZfl>ByOXOij_L4W75d z4d((!+s3%JE4{JuXaT!IzfGV(#ppEpCPTREZ=O^zo=K^@78D-8NP9`{~gl$|I+w>$!TT(=D(_o z{{uE9U}pIyN&Z#!Z%!*K`?r4fZ^k4&Jv{*jBeV8*wWYqPJpuE#J>RTaC1VEy@^45g zorxvg|IBOsMzsDl@c$x2>%Zu%c8T^v??2qvza{@pEZ-NOg_W6r@f+9sx9snhk&T_;pYp$T{~zh^v47LQw9peU zGc$h=CI$jFMn(cw)^7~(clsyK!0=B${^tLtf7)l~_-}RW|B?S&_qV_Q$b8HG&9i>X z{#%aYTmQfFf6M>s`IqI)tbYlr|FYn()qgGd_xA5m|L)1ZE&jXzH_!H8^!DG@{jLAE z+&`B6$JzL+`+w(ZFnyoh|FxCvdkFj|I4r}r*uNdezxc0z;jr}IuH#>OjNi902mN0^ zW^8ThVD{ZxrvJ7>z`(%v-R|Gz`xZC1{Kgl5J4wrLjIpq>p^cF-6fZB7y~8)x*b2&J z^}xOF z)UPZolAe*`elV)l;+!5V^rD~E0jFYuX@iG!2g2Vj~VZGdoxS1~4Vg|yxY z_f1#0hZ|?#t^pp59e5+-Yt$GBBw51;*D8W%)4t1(!?*mia0jTdw&@ui7z_ZyOdp1^ z4%D~jivDWZ+wn-(5$Ln&Gy)gbisy6l;@WxM`*-zkFkq{RlxX#pP5V^NuA|24S}}vq zU-Cxh6Sx57)L+$UE$p9jM^GRi8w9CcCV`I`{xvCn9Tni+FlLec<;UCanMnM1-bIXa zU+KeNz(`+F5bu0MSKe~#-b=^c-)DH^?)_>ymbS4mbkOMv_&N$2?AojE58&;euFK>v z;%}MFP*Y_E^^%gr3pC{ySS%Ye7Ou#D}iT*Z5r%w3*H0)%e!IOB!2UaA0s~ zBGE_JR-v~TMOWEn`Q^^D>^a}5ye<9P)POEVZZ6y<0G+5RtrGw-7xdDbzM($&we9uu zJNnBfn8C-=&z@yWqXW2UPrB5AhpXAIy|1c-&#oTvk-CxUOO6DDyn6qpxgRQQb`*YKktvJn zJK_I=^U=_BaF9-LuyvN=p=ab~UiJiBYZDUA!VVH2IfC*NL_N5Qmm4iq%f@2m&Ful3UuhwdsX7O?e;P^74%A zx|PY1{cfQF1Vwv8eA2^D@$yWI&(1^ah50mC2?0+4XT&(J?q0~<8<`lY|3gj z3_l$T`;*)7&(J7Cr0Ws&=P?G=v=OeBl*E8jgDnRpCQo1>ss1CxTL<)n_z#}=181F{ zZY{n}(m93&6c<}lH10FH6k$iCtPhU}h3!@9GJHHsd?*bhni=*256!evY2nr%P zz%>x%MZShoF99KZFImLA)9Z!%v#K`~<*nYZM^Yd%zxNFjXDXhUSwbwyh(kn(MCBae zdqbNjRXX-vtW9LofNU=%k~cCh-osMdB&ZWdLs~3ryez}UY|5#oV`RNi1eB^(rSFn> z;!mXYBr=UfFjAlw+xd&$d8qpQ2u+y^5+Ea(hR1cMXV60z)3#nwMpP!&gTh&>u4k&N zz|PqwGC`wqJ59j?C}89)E4%!HZiAe18Z2keL&s3T{ZR|hrQX2 z`?P93+K-IXi~1NowCBxJtnnyS__%PuH>R~p9G6@G?K7vH$Jk(my)ZXFX*M6`Dfns< zktF4fxG3wcCYm=jIaBQB@9dHVC0=gZA{G|&H*sbVvr6XmK=bAI$KWf2KGOzR9`gMH zxttGRLEWFDpYS~WL8dJfyG69gM{$r@5>vS~%7sQwuf{%(_H?+Otk&qpL6~Oy{>jo$ zuv0N7aeLm4f7gc{g1eKv+FPib7nJiOr(6$8H;v7qg=%9|wfwQFBd}G`OuDd)lWLCg zN>wV5N4ecdR~OpT*TrCqe>&e|GceWhNRz<|Iy?N58M*!WY|>PlFfq0{Cnvu#9mA@( z>cgxC<}QNY{O2Jf<#nr#g1iyVI@j-CDZ<0sYlUzM)1eTKjYmB&wy*6C#>BfhW^1s6 zuv5$i`{z#`wQq5XLXOLk5QID3^D?k+rn6z@m_IF55qiDC0~IcrthgARcNa8SH_IyY z3rJ0=Z`#kXQG6U!biyEFyKR1u3|oZ>K#8>;qhq}U`C%^yEDStu}a$}?|DA}Vu!ob+Xl=N zs6Ch(gu3)osPLrYts< zU%?fsG5&=t)YeQ9mXA3Tr5UA!5WGpr{ zp?phSHdy%*+m#Sj7X_el!btD8HqP!5v?Axvb_ycGysfPx5sh|N6g!HmNBOg3+Ne6I zvv!1JyNSZOw6IE|C`Ks%KR1ZEgUU-@TMie26Vo9_EvnBWT>Xz@i#rsc*y;K5O-@e7 z_aji?sw{uDxV;pSKO-YFmy)W`S}9Ti<9J$t$LOKQ?r2I1H(#Uz8xQ9 zwA9~5Tk{3i5-yw#H2;vdRTM}6Ml>MXiG2q{!>30!Ld8V71p&EbEwI^ovz?l$n9#MY zYvGAf&UkgK4OkbAKWUZiYP`%NY?P5RkmB&d1;4(^-X)>8ww5||cGc?j<(F)V%dL7s1Vu5ur96m;TZO#?!Cf zOA_HA07>R-4@>G00}6PLHu{o-Dbbdfcmz0squB@O6A*1 zQ?%xD zby!QpEWB(EfgS1b%n3p##qVqM59@cMu`(pvqX5t5rt`@GbK;@bWqjY?h*&mINPQwn zPs6n)Xcug>zgJQwtnQ!%-ZI|i*<7Wxi?_&?xcLy0*c4s9|6-MHUs5Mhus&X!h;Iwl z$&hal5hCx5bEWL%-6R%zaBPr=6MjeJ~! z!B6MgZl2YcUoK)z29-_vi@eUTr3ubb63R>+%LREV-k1E|^dY#ay6gPVf^^&H^5lwkD>75y~w#wbg90S|2In(7J9D2Hr z=^qijWf&93S0rxC^uz=-fnwI?n&o+MB>r*=+&i4VtK=lA?i< zs5tXfA_RbC6bk4K8_y7Oy z?|Xmuy;x`OwbovH&3o_j&dAYQzOM4t8S5&gcj1Ff7j~(PPMP-B)_dw;jl7g2k6-;+ z)oWNv~o+`b^f>y-1^MdvFq>aHZHsA>RT~5 z&uWgouI`apt+PW<7kXWqSDKW0dFH3Wg4*rQ>CeX=2);Ho?%S%^nzVtN^9|G^*#qzI zQ*ww5t!_BY=~X$_^;M&Hw14>5G%PUjCfuy!emj?x|Xj$bX?GF5TXD zjP3qE+peki%57RZI?^xhiFj4*q7NC{dM)zvn(|@%iHC)Y{ltZf9wi+2oE&C7)iPyQ z$KV2?&*2%r+IKgx=nf4*kVmsaFd7gG%Vm6-LWxv^Gdc}pRqY)=gq+HFaJT*0O zYt3Y>nG0^TuIXVksK|d~i++0Jq;LGR;F>+RBDDN?qoPcAY*cSfKJc<%dKynD!?Y>}dOs%6+O1r`{hHeQJL0K&yJ&oI}eZ%37~lZ(I_+vr~CuoY?pr*RwnP2acP%w6xc=rDcSzrgH#WRc*XmylIniZUecv}^NgiwV73R*pW)XWV{!#L!)phR|XVxk``^M62h5yil7hBRkJ+a{6f>%R- zN-Oq#iGDxt?UX%7tdm#HHjFL2S9>eZ_t9cIgCWiNg)=9nzKB`o>F)PK*=qk#2fq5r zizeOD#wm60snpLqceT#MU99ETR1a9rzZNmiWTa6-VCrJWM82|bWys^T>EWp?P1%=pY}yqdv7q_b{2<(^!b3;!v>&S|mNdwV;?p6~oxwkq*Z*TGj$$L?>w z@8|L%%89*RINx*9kG}TRypIoNsh(P!E4!KgGuIr5CFkCR9{R&1s4B&_CckZeMTS#iElAU5>umssC6qM6O=oKoi3XT?|^O&8?&&kT_f+ZVE3AqQ(l=~Ixf+7^2W3e>Zn@ye$~l^-33kY zy<$~5ADQSNyO|}KJNvAA0UOds&-{#|keoCR? zp$|{$Z~XS_&%oQx$F2Gt`+WH5_T2-2Zcyp@qL1aa>S)>0VNasOoA#G%sj8{oP!cM5 z;(th{8T|8MpPB{dwriv5TD-oq5OW73X&UnL~;8=7#~ zB-L#F!@Hu+SGkL?glbx36`kDH%fBY0kh>>7VehM53+A+@el0s}ZPR*OZ|lIk%md4I zn7RzFTKc8F)BHM31Fg~pL0zqHK8PAC+)^^uF6iFvVBd41Pm4?+9Um^tnRLcN^YYRC zOYU{txKg#Z_3N4*W|z;N-`&}^dhnY)&fQr4?bJLov@MVCw@xwYZ@cD=R?D#Z(X3Zl z`d#`|t+u}%l9ivSdrYTmn#~DW`j#;Rw5o6HF4rkB=F~nYvyfSvHus;tOIg{${Qagm z3srPBzAPMe?0u6)$qJU;lfimf`ugIb8+x6zyZK9r+~dRXTKymRk3COviVy9uY-4gBEN zuVcc^t=BB8I5V9tZ;CXH(w%qx+@34J_kv9wUwQwWcyo{Itr_Pfs=3_9>$T_I7@3xP z*6*WTLa1_y+VI24H5c0%S?#^CN#*-Gk4c-^w|(0EKJZo5*vmV`ZM*vZqUN5DCslaO zll-pH?PxR3dZ)w9f~M19wF=*=cuaA=`zD&$!&J8$Rf__XBNKco0GGn3vX?FIa^Y9^|trS z2wjhul|8=a{4Bfv`^2Ly+&`Du&3g(?=WUtQ$2#j*_tpkax6yaPmss5MZfDvjwr{4o zch&o~#x;Cy+=A0_FT6cC_l~R|RMhwSin#m-o1EV6Sv&gTvwi0>mb+ewsk(c_iC0$n zd3tkW)-i*u$EiIBI(+PYYS2Q<==pc+I)A#Cl(|S!Z(1@;BWHb!Pq&L1TCY#9=p0y+ z&2}tzX0-^PpES5;JKtvUYXLuLkC zl%C3TvG&)R-?S<8hR2T%Jf8cYSJ`}aQ_}j%xrI0M)ZQjtxvim^Fs$U8MnIKa)0oVn zE<ZRCgRfgvY$^TSH>TXdUt7=Q)t&Z-y^R! zoqg{Vv!irMI&1J;i>u+04IgC_XB*9#{%N2=`04$Vtx^t+y>nXlbK=j;fY{4VR*&h~ z+B9nC%`oe<4vSyp*w@VrX#d!Ke35Eez@+)26i)29uKC=ag&y8c&!e|}+$N2Tzdu9O z+eA9S+* zQR#qPr3NprkF!~Ji+e3~PQ|?rrXH;QolF*;p0$6Q-GE2Ey4RT3^Y2zzo$Rzf!=bxW zt*d!e!?rA+%yHMHY31*DU9(O_bh$c8f264A0Jy%eY=W!3PhpvL!Zudo;Vq|M7u;QB zwPcQpI`^$n_C!z3H_CDRjy=qpUX1^xH`^jMeUQ{JQf5*zwfBaeY3JkfpLFBj6g~7^ z0uJzKSk94Zzn1C^skG#hS zw&t#{(@t37I>E}YXJodc@8>;p(n1aFs8;dqYhs^%ru}Dik9z$>zcR?i zs%C#=@X`alB*{Y#`t(_tQt|qCV)gXf7ssb;+H94wE_&;UTO$W;A6y<&`?27?cmGaN zciya;wko<&ze{nkv_n|Yx$(=_oVnw+_khX8hU1%kYs^pDZM*iPyJ6nI*zPxu3!la>=`A`_v7~Ik&UdduyCa z9ntM!$>0yMUHm$S=KW&3tADMYcjEBD(U1BjwKHZd?As@K!tUn!LwYAYf;aX!V-$Ac zVAPwhHB#e}M#cfh@CW`h+Z9&E?y;P+OOA{><~_pgW=A!noekB7N2*sp z57Aox<^#KFA-gX(_?2*D@TyMtE6OkK9IbSWeQ~<|&ol2Abyw0^7-Ri> zi~CL4U0J_{oAqo|^~SD)wm0_5CXm(}ZPV$qRB=MSW0_xo1p@MB)) zor5|-0ptDe9J2iCbLrlt;fBkt&F8KARuc27s)v_z@1dJZO+V%~bkP~2mUMoI;VZud zowu|<6+EllyleSqcVqSQojVJ)o>o2V(o^#}y#Cm|B}_ej@M`7X{Nqs_F%u_GNN<@=WfUCnj6*M8qQuj?0OJvJu;>UUGoC=mF`#BvF+%xJJk>E2PIsYasS59Ji7_|Vpbgs;(YEiuEj%rW$5s@ zN~;bNZd;!i++2F-oO6}#rkTf*C#y^tvQbG#*xZoE@4cPd$@TroYbEiPy>mU9jv7o5 zzkeKcp*FpYkx!rMZ`l+$KhIsbGpS_I_5L?Ey)(~j-PKZgChN_VrN%2l zo;JkpxvgBL5!rRq_1w>$ZHi~x@NP=$_~|<)e&WV|Jli8xN3cf2+0;F~)Gh7Qv17?1 zkNHln+rk$Yk8w6w7S=7Hu(!LvUXnm3ye0g~k}l^m@72AX{b8qDU{u!S>+U)c0pf9^ zi`4>_wH6kHTP!d9vdnjd>?FSo=QvoO<=h1hee&Yc}j8 zdns>&i_@NwW*U_1Xo){65|L$3KrgHGG=KO;6_Zr8RmL7k>ZuqI)Y_)6pCoNz5 zDKQco%XxZT^oCFFcqp*@_g+)f_LO_;Itg;~e@XX_bbh<>bH(%1PaIo5_2@P1+Z(II zW8DwBY796VcV=n%LiKJv^xAiGYIqy7HGgJt%kS}G=f*56yx&2V6x)wy&24*APMBYAg@Ectr&g-wo)-{z`qE(Mzo zik~G1#T4w;oHN(5)BUfFos%;omd(tnw|>0SPfOY@%>U52IjoP4jaJURmGuYn*#_+7 z+Q(!bmiCmb(AhkI>j$dN&Oy{`fRrB z<^u252^t>$%I0Neeu>wn-5>s{F&}}&NQew$7{KciT2tb>pdIXU2h~l)aNW8cWiRi{1L&) zdQ19m;go;9_DXy8@c7sY_U)WI!!-U>2zqF|2veypS{z*Qd-Ha;4^twXytkd7_xQ@! zTgFRoSY*r}^l>OhZ}BvjyZ63EX;0bhaBsvu!M7oKlTtWZ6I%RT#F8FRc&Wp-i@=<6=a*|y2~m;IVo2d;1Xrn>k}$puzIb*C#HyZN>KY8v{R zMq8$++#Zt)JzDz_!Rp$jJ$`p{)cp}-u-7v#Wtiwm{s_JOc9IF3r#+MM7aaVtc$uu{ z8cpGq=~i!hMtyB*-r`zxL@J3{ z8L}i+t0HOmvfwElD}2M_&d)ghCC?{HJmNyj4`E!GelOl9-+gE6^>gR&^-7)_zJES# z%kIVZbBenR;LZ54#B8U#{q+8al{~~RU3X0OFufJK&1J>5vMyc&*`{Nz4}E1^cRhDj z=4hX~C!$2R6O)Rx`d&(Q{_xNx%H#z{q_a47`AUz`c79W9oZI)W`PeisTh{B5vq9P` zr}DScmx(loc%7Xx@*c1DX-mUcm*a0fF8aCl`C8paBX9f`D>(+PYu&YA{Ku6Q0YgUY zU%H1ME%wj98t!&qmha`+E+9T>(mK^{T{aBwSw66_x$DF=ZZC_RbX}d6m|tt?kkv7& zcsKiQm6ra(mDjsBsK@`F&R<}h_WH*$^ZJeTd(TGchu7X7f7>qAy|}$o=K&@*jnx)A z7vHoBz5ArlYt=WK(=oYf;ihvgE-kp-uEkipr1#K_(}s`DcKVl1 zT71-TRnx1!*Md^ZOP0*$&zUxLU841MuOZ4?92zz_K1gHD+p?uX@?@3jK#QYc4dy-9 z8wYC{_PCV%^~c)loEJUezc$z}aGZ6AMWer)X)HUXG-O|#6VH2wea4EtYJE8hg1Q*k~N)z)vnl`$UOJn zap17ViJgzOo~_;b?&t3xJqA2lJnLn0*5tFAQ9s`dEUJhfy{|>LX=Z@=y{xbGD;xH6 zqfZ+h^c$&R63uGJ+GD8E=p2_c{Ss$tq#bLuO!?rW>r*sOkIkOjxOTTJ@=oBoNqe+L z2Z^3`{qrJi!H61;bj$2PU02R)|Ff*@N^DDU>-D8wn#}v$h~L7CT=8s^>Vd{~%W&6HvRwPo z-_Bt3oLd*Ao*M$%^*#75^~u>5wV%2y*ZA0jP3>&zT@Uv0UK4pusxr{@$(L^3uAF%N zRG7O*w%KQz)v)8K-fNcsmNY*cH0^53%Z~P?nos|f`M8O@Yk2POHJE#$uiAdgTgS)# z@NU}P)TOAgyMbYkOttxY_WsBoy=CjCTVAQRlgey3&#H$EThJmk@)-TFeYfsqcdtcV zaNb|(uN^<&$h?P79tT!E`ZDu@UtP%}&1%W1)U!*YqfGLj2OLr|Xqj|sj{cjuX1_PR z|6O)Wb|u`Qf6zj+prk9Qxhd6)jy^bl**fpmuYR}2IQO&Jr{j3F-OSm|O_s?wJVy=s z)yZMHh2~5nwXveTYx?a>n6ul(uq5Z}dr4z%k}NK8)te&Mpdj|;@O7j1HM-vZS!}^` zU>y#LcFxH=Qu5Yit4EBsaeeSziw76SdifqXUAMvHYu3t@L+!52>n4jT?rVE`Ky_jG zsOwgR*6gd7>&}hoGxAyO>wwf>n^*rDwqbLv=fY_(sx^BJN-I3X~+eK$W7X>=UaV$`Z&Aeh4Ci3OT%kJ&YSAK zESNT{N%&(%;;1gBc4a5mbX=vj=B0A}m&tc~w%E-mYyWca^~BDtJ$sLg$he!n!(!CY zsHtn8PTw;($oOrLbzb)e&hM|@SR1`0V^V;AS*rBPW6!TIcgDXk-QDqsS6^Y!laM7U z%6kq(*)41BTe_rt`Qv@T+uxpYRb3yVQ`ya|Yva1s<+8qBwg&6X{n93{HvRqUiCy3( zRsS<%{pKF?2;1D)ls(IRc-*F8)*0m*qULKA!{WbhvyPad^Q(T4&+j3RcgMg-=aq9bUOZK5?%2FOU}Rto>zQ=8Z{GEH)eXgh_qqMEt1J!wGG_fk zzfMthDO&@k&-ku3`1Lq8N2A#{&Z_S4)caH1w-;#-*k1IkPxh_NjkTq@?~|`KnQu2< zd_p&6^Q8T2hKw8-xyrw5((irG@vDFa?T z`IJ@YnE6Yfye-kDVYIjAyeZzQ!`4I|J9aibwJN1JU}W^GNmGQM-_-u@)Z5^7(uk`L z@wwm2-5s8o{hE;1^gZ)nVpht#*?Bpk-o3K@qVyt*R2>&cqJIh0U*u3)x$9)?LA1U?a z9J}{EWK%0=`>79a#?5utY?(0X;+>ycAI`4dnHbTh-{Go5vYXw0efiNxLwDp@^(oDU zM@?V7(?3^!qeWc3E#1UXqippPS<5`F;_Cg!eN1#C;vaqYI5GS~8cX})!N@&^M$eB( z4)^`-=Db(m-ut&f^@?>b(_dt~tsW3LU$tXRW0-QyjM<$>d{y%6nPILnbl-dpuFeOQ zZm+|7?e~4hKdC)*ynfO!7mwSyu2l7Q>>OS;LzgvH3x!j{W?0{!aFkc zm+PCWffwfcT)nc!@9GOcL2+SZ9f8}xR)>B=t&dH?Wmo%W=QR(0#k zaud}biPBBR^%b4-Rq^>~5}rHs``fBV3B!BMpBt0$Yj~?m!)5b0#}y5$oECJ?E6F=? z;N{>2En0@1)9h{*DUaXra`zL7z0=ddoLN>k_IHj7e$Jcw8E&Y4G1wFskv3sZMA{YQ zTi%8XRp(cz2^zW<=kyIZyr}(4+y2spyLxSL&>48{Cd+`k-E(Tyjazs6MfbX6`EHN- zBi8K7toEutlLn907A~7V=3wQF{{Fjki=rCVe*4q@cWOI!ekaY<$%E=QmPKvOL25J=}a*@N~x0&y^MA zEe-NuMYsj}vHX19Sh7$*mdqp24c?Ua1qZ^bn-DivkY^Yx$Snls5HEOGzMe49#m^g_ zx3s-;F=LstCbBG8mMkmQB-Uis6xKA>be1*ChGol|$+Bb3V%f7CShHDk|M6pzjkhT+tgP5NQ zh9w|>^3f7zYV!a+@soov!{2=3=X`h?LO)*P36Y%s7ot1?!GksrUYrrgMd+ap5D`$~Ki&Su=G1SrsH2}F0I|DyS4N|0v`1>zZ<(HyBloW!3+6mzm-hV~L zgV$c98B7( ze|aW8Rzxfz91($+S}#Mi1S*PQIZSAE3`}ji1TjT^lctQ(CKlmJCf4 zw-oDt(Gs6BxNX}q()(gMMKDOZKe^2(h$>x5-c z+D03OSe`V#lVo5%SS~$@@r*TjEm&+P2N((L(+Qw`5L4=>(Z?$_at^R1qz&&E6obmbW(r zA@Im`lZHXD{#VtAPZ?<2?2USdPlq%Gv|MT>gx*oC|3yoDs)&~Q_6OK}G8Ou_Y{}e% z5(34#99rDoxNRPgwy-DO0=8?#Hudik5L=2XXtOm%QxnpD zlj4(F0>LNkGRQQ_kT1ulP@!%@O$eyN^e6hc7~09CfieS#wq#kPFAbJ?_yrnhb4gFC zO#zH}2JjsONa3~h7X>d4f&pZzK>mq7=1|3q{-OwTKOg@eL%1d z(-l52;sYIW_vJq#z*Kn%GtgHC{G~wHAsYP`Ow%Cr6#s}oM=CnwLr-5%kOr3wfB*Q5 zqOY|K($1K2?h<%y*SvD^;ZahXEvxHs)x`hSZ|S zNRGHu_yo=3le&XGgRfv9wui738bDwsy*>?c@%9UHL!u(oTmedqCJl;)FLsj!`vwQO z5vbcZM6}vIA!oIz3;N8@-^~}1Xp8C@8ye^-L%fg)8=^@-h*6}$w83b$sfwH) zN`T4nZNvy16bn>2Mh{0&l3!}Hi!{VdDnklSep`>WJ_SLR!KViSo1QLGZ$r1hK*Gjo zsY9z#?gIibnPO|}yHbrv_&ymxP775IiU`np=jOABkT9)B#NPxu+S-7!p@-Dh6-u$i zXdbo8@?eCJY=UU(dw7HLz*lv+OI?V)CY+HX7!9Y59EJx4Lz^)$9O3>um;xeB_=G0{ zFXHLSxJ1EeQV5I5DC@W+%po&6k_LjoIymyY0E`bbU^Rc|@rSk?q4F$6vYvwg}m@fK0dPabjc(0{J}`u*Cv|PhS5795J$U zf&9J!Ohmxs^gzI43qUSHGVP;iz^MwXO-P>p&@eDK1e4P%0S~@W4Z-Aj=5YjI=R&Hf zN6L!F5rPbaR5!K_hUk(xKTU(rMKpNw@&m7g@F}bpybUpq-XmXGpdShmG;io{BV;WU zB5%({{(*jk*QZ#eAZU<)(pYa#A5S8TNfZFc$+tlioIE|O4M;k9O4+^rLJhs)^vD~< z14_Z#U__vyEWpRj$1gD4&`0VEM+iP}Xn!G#O z7gAk>irQ@SCz?%XyMF%Yi`s(F2#OI3LXe;Y=Pz~f0mCV#MF{BHgM^?(&>02^L5raMBnd%_pi?>mf;O2t=pb3< zp+(S+j~s#)A)#!6grG(I-DKEM_Vk`Q75dB7|gr zfu4n&25qbaW!yWEgU~SA)64u^jEs!h+$xXuK_r}XOz`b^B|q0`T5g+nn&05 z@}CFGJiQIwk)!0xGfpkXNRdS@bqq&Ppog@Hi9-itgum_6zj1;?CoJ-xQ(m6VBjrDm zUmKTB_~Zx3tqs0{@UMJn+QC7D>^Zb8%Fq3~Zth>Xw~2~Nwtlr?p%e_M2d&r?eiRWX zZKElI-=X%IqRplEg!r2X+LZH6xImXJ44hmkjjwhPzo&vB`^|TxP3B>$RHHEOZtj~6^{xLdvx!MK3OCv zD-J{W>0xlMMux8R5Gzw?b0JC7qsTi6=2Dr|+ix-I0K(-2m_$fcnMI#R0)$WsXnzuI zF(G|MfyPgVZ>H2{*$26`jfRO(`0U3_@$*8NoaVgCre8t`S#Tf418quDQ0zNPrZ`3-;Y3$W5vZuA7>H z;Bt!&3v_c=hU+LIjxs6;h=1U|i2&U=aM%6|gHVh9QGkH}F&OL+1_R%Y!ChYe7zZ^pa#r#%z{f!qpF9kH=b#P&6NV}@1sD%9 z0LD1L$3|TPg>h^)7gY{S7;-EMFt{v$vQK#!WZ4o_&C0{zcOG)dOc?6oE5P7x3`+9l zVSo?a5>kM{A4F$DejI|KNUH#YLI!oX@*}EVg>g`SBUdU91AHQs zBFV$xcLBCG)bU};8R|@wjmpmjd_;vN4};$^IU^X#loZAZL_8E=P!%H&gO02OWg7A@gb$^r3>Xh} zCgfpohC_5KX!)4D$wK{_aaoJ5C#sRCu{gsHg z$SFS#_!FQklL*Qge%@XE15I%J7BtH(# zW!e#fq0C5r97hPnE@R&SA5r|vkAu0;&QhF9AxWa=Dq|bQevY282NlX6I}!4^;|^ z;~?Y4^b{IQm>ofLAKP=dFUlAP9WFNN(8$x^3Za3^948b&J6drZgd^f$Nq#PbOA)I1 z6=C3VFg*}RP{k=f4qA}J{bU6gk1b*D5sVX|CYSs;po{GXIC0G1b0GvU{XJ~B7>_eT zkUoX2AHkzKDsYF=Lzv%WXO6$d8Fn!p3zH!UuCN!R=x(iUTPPjt`Os z1`UuEvv!7*0k8d_)qvI0T$CU%@v;Bm|De=m${r#LGcN&bV$@DokQHb+rjuNFNrKTu zPKP-c3>c#eN{-P0KgFO%(>WHKJgAo zkuEfrvAKK!zBV{q$LUH?n_UqfkBknn7lwwi&@jLAv;CQWrcMhHDJmV`a{fo zgAF|%ES|&BB_?|aZw&E6HV~4igJe3k?!T`kdJ#gOmmu zP7E55@-u5csC7k5n}(tm_xI4^#^alW&zuXI28o>_T}ZBolXZEy08GT>g$-AGnK}tD zF|%KS<}&LP7$?DO3%bvk&A>XCdI0!{+mj6bu)Y-PK4ZBGgf}cEL(Pfhr{L?b+yWv1 zR=>f$IIO=5_u`oS95&p6`^UI{(1k-5W{igiu9y#lvWIEEY{+)8{1n{?!u&I|+%Ot& zIg8Gj6ZNM%-9WGYIF-u zQ8%Dphm8~A{aCmWfz>#mLs)IVhx(Vf4nFkFFuEcx)^F!S(#n)QoYiB!D)4n!u8hi1 zhL3=_%Ew|Oz%U($`+``H0`AyibuAwbt14x&uplYnZ6k20)vYB0#P69@4~%A+y)_j;B-Y|tRDt1 ztFiS8xL7|7PNO7PT>$6PEPp*}iOrl|MN;13)V6d(*%1mzBV3y7XmtNSie}r=P>;S zG(xrG>BpP@iKq2=zH; zTL8gy60V$Jbj6@-Oj*GxES8&z|B=(c?FdZv0Kt_Q@%(Qcui=Atrxy;%gZohz&P~1y&BL*J_Z8L@r!8qb2jl8czFs7aY z4C@U;uL{dgIUKlq#PIhp7t?!~i^U#*VRngN%zOi2;5-@Y1zwo80K8x^0OrDl8pXL_ zGgyBTND$whq#ze`iG`t8fbJh_gQHZYUV+*(&wC&f07F;g1z=cz9JK_Q^$d*TG5Z!M zvtascfI-oO(SXRxfT80GhJ8Tq5E{3PabSX2p9@-Un2w`19CI#|x=hsLw^#h z=>UfHrC=_0cLv76As>ThD5ID)9rQbKnZoTgW}F5s#qMarT&P5uG$3bX>IQV1nEnsE zDUW%64)~x@X5d5D6B&96bKw>rHV!f@MHq+*I&6wC=*MEca3~tFGf1F;_d8)Lv9-Z+ zF*!ral3DMgBS@xiNBv@aZD7*a+F&v!Q)sv|)(dNcZXa{K5-bLQC&BKi0*uehPm#yL zc!B;4v;Kf91bCksj>a(lAX{VBBWdPMa<|E+i?U*?dsyMNnMhK?B*drK+ z-9H5w?q6VwnE5mC4DWoIG5|$j>WdJBimd~`>jL=j^EZHDb_8h-GcSg26Lu#H91eDF z5BrAIZ!nH{rK=!&)G}h`L(o%T=B$V=v;TtbKr(9~fDsQr6=}d7G>itEM=@mu>WAe5 zP%~k+C4sXJrX4}s7W4OTZiVS2bcZlq6NzEPjQxe06Z6?3V34Wz5J9n+EP@mSTQ7Q| zu1Eu=44D1Gi5w<-F@BbXvO0_|l#*DzAO^R~po^~JVEF;`BC)&)I>XHUfc_-$Y*2oG z;l3kO2aL7B@fLH>;dFucHcW-N=(vZ$AN0bpmF?)y5 zF~VXLf-(09!I=Ol1)Y9 + + 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 ---*/ +/*-------------------------------------------------------------*/