os/persistentdata/persistentstorage/dbms/pcdbms/ustor/US_COMP.CPP
changeset 0 bde4ae8d615e
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/os/persistentdata/persistentstorage/dbms/pcdbms/ustor/US_COMP.CPP	Fri Jun 15 03:10:57 2012 +0200
     1.3 @@ -0,0 +1,1204 @@
     1.4 +// Copyright (c) 1998-2009 Nokia Corporation and/or its subsidiary(-ies).
     1.5 +// All rights reserved.
     1.6 +// This component and the accompanying materials are made available
     1.7 +// under the terms of "Eclipse Public License v1.0"
     1.8 +// which accompanies this distribution, and is available
     1.9 +// at the URL "http://www.eclipse.org/legal/epl-v10.html".
    1.10 +//
    1.11 +// Initial Contributors:
    1.12 +// Nokia Corporation - initial contribution.
    1.13 +//
    1.14 +// Contributors:
    1.15 +//
    1.16 +// Description:
    1.17 +// Store database compression code
    1.18 +// 
    1.19 +//
    1.20 +
    1.21 +#include "US_STD.H"
    1.22 +#include <s32mem.h>
    1.23 +#include "U32STD_DBMS.H"
    1.24 +
    1.25 +#ifdef __WINS__
    1.26 +#define __EXTRA_DEFLATE
    1.27 +#endif
    1.28 +
    1.29 +// deflation constants
    1.30 +const TInt KDeflateMinLength=3;
    1.31 +const TInt KDeflateMaxLength=258;
    1.32 +const TInt KDeflateMaxDistance=4096;
    1.33 +const TInt KDeflateDistCodeBase=0x200;
    1.34 +// huffman coding/decoding
    1.35 +const TInt KHuffMaxCodeLength=25;
    1.36 +const TInt KHuffTerminate=1;
    1.37 +const TUint KBitsEmpty=0x80000000u;
    1.38 +const TUint KBitsInit=KBitsEmpty>>1;
    1.39 +const TUint KBitsFull=KBitsEmpty>>8;
    1.40 +const TUint KBitsEOF=KBitsEmpty>>9;
    1.41 +const TUint KBitsNext=0x80u;
    1.42 +// encoding storage
    1.43 +const TInt KDeflateMetaCodes=26;
    1.44 +// hashing
    1.45 +const TUint KDeflateHashMultiplier=0xAC4B9B19u;
    1.46 +const TInt KDeflateHashShift=24;
    1.47 +
    1.48 +class Huffman
    1.49 +	{
    1.50 +public:
    1.51 +	static void EncodingL(TUint32* aEncoding,TInt aCodes);
    1.52 +	static void Decoding(TUint32* aDecoding,TInt aCodes,TInt aBase=0);
    1.53 +private:
    1.54 +	typedef TUint16 THuff;
    1.55 +	enum {KLeaf=0x8000};
    1.56 +	struct TNode
    1.57 +		{
    1.58 +		THuff iLeft;
    1.59 +		THuff iRight;
    1.60 +		};
    1.61 +	struct TLeaf
    1.62 +		{
    1.63 +		TUint iCount;
    1.64 +		THuff iVal;
    1.65 +		};
    1.66 +private:
    1.67 +	static void Lengths(TUint32* aLengths,const TNode* aNodes,TInt aNode,TInt aLen);
    1.68 +	static TUint32* SubTree(TUint32* aPtr,const TUint32* aValue,TUint32** aLevel);
    1.69 +	};
    1.70 +
    1.71 +class THuffEncoder
    1.72 +	{
    1.73 +public:
    1.74 +	THuffEncoder(RWriteStream& aStream);
    1.75 +//
    1.76 +	void EncodeL(TUint aCode,TInt aLength);
    1.77 +	void EncodeL(TUint32 aHuffCode);
    1.78 +	void CompleteL();
    1.79 +private:
    1.80 +	enum {EBufSize=0x100};
    1.81 +private:
    1.82 +	TUint8 iBuf[EBufSize];
    1.83 +	RWriteStream& iStream;
    1.84 +	TUint32 iCode;		// code in production
    1.85 +	TInt iBits;
    1.86 +	TUint8* iWrite;
    1.87 +	};
    1.88 +
    1.89 +class HDeflateHash
    1.90 +	{
    1.91 +public:
    1.92 +	inline static HDeflateHash& NewLC(TInt aLinks);
    1.93 +//
    1.94 +	inline TInt First(const TUint8* aPtr,TInt aPos);
    1.95 +	inline TInt Next(TInt aPos,TInt aOffset) const;
    1.96 +private:
    1.97 +	inline HDeflateHash();
    1.98 +	inline static TInt Hash(const TUint8* aPtr);
    1.99 +private:
   1.100 +	typedef TUint16 TOffset;
   1.101 +private:
   1.102 +	TInt iHash[256];
   1.103 +	TOffset iOffset[1];	// or more
   1.104 +	};
   1.105 +
   1.106 +class MDeflater
   1.107 +	{
   1.108 +public:
   1.109 +	void DeflateL(const TUint8* aBase,TInt aLength);
   1.110 +private:
   1.111 +	const TUint8* DoDeflateL(const TUint8* aBase,const TUint8* aEnd,HDeflateHash& aHash);
   1.112 +	static TInt Match(const TUint8* aPtr,const TUint8* aEnd,TInt aPos,HDeflateHash& aHas);
   1.113 +	void SegmentL(TInt aLength,TInt aDistance);
   1.114 +	virtual void LitLenL(TInt aCode) =0;
   1.115 +	virtual void OffsetL(TInt aCode) =0;
   1.116 +	virtual void ExtraL(TInt aLen,TUint aBits) =0;
   1.117 +	};
   1.118 +
   1.119 +class TInflater
   1.120 +	{
   1.121 +public:
   1.122 +	TInflater(const TUint8* aIn,const CDbStoreCompression::TEncoding& aDecoding);
   1.123 +	TInt Inflate();
   1.124 +	inline const TUint8* Ptr() const;
   1.125 +	inline static TInt BufferSize();
   1.126 +private:
   1.127 +	const TUint8* iIn;
   1.128 +	TUint iBits;
   1.129 +	const TUint8* iRptr;			// partial segment
   1.130 +	TInt iLen;
   1.131 +	const TUint32* iLitLenTree;
   1.132 +	const TUint32* iDistTree;
   1.133 +	TUint8 iOut[KDeflateMaxDistance];	// circular buffer for distance matches
   1.134 +	};
   1.135 +
   1.136 +NONSHARABLE_CLASS(TDeflateStats) : public MDeflater
   1.137 +	{
   1.138 +public:
   1.139 +	inline TDeflateStats(CDbStoreCompression::TEncoding& aEncoding);
   1.140 +private:
   1.141 +// from MDeflater
   1.142 +	void LitLenL(TInt aCode);
   1.143 +	void OffsetL(TInt aCode);
   1.144 +	void ExtraL(TInt aLen,TUint aBits);
   1.145 +private:
   1.146 +	CDbStoreCompression::TEncoding& iEncoding;
   1.147 +	};
   1.148 +
   1.149 +NONSHARABLE_CLASS(TDeflater) : public MDeflater
   1.150 +	{
   1.151 +public:
   1.152 +	inline TDeflater(THuffEncoder& aEncoder,const CDbStoreCompression::TEncoding& aEncoding);
   1.153 +private:
   1.154 +// from MDeflater
   1.155 +	void LitLenL(TInt aCode);
   1.156 +	void OffsetL(TInt aCode);
   1.157 +	void ExtraL(TInt aLen,TUint aBits);
   1.158 +private:
   1.159 +	THuffEncoder& iEncoder;
   1.160 +	const CDbStoreCompression::TEncoding& iEncoding;
   1.161 +	};
   1.162 +
   1.163 +NONSHARABLE_CLASS(HDeflateBuf) : public TBufBuf
   1.164 +	{
   1.165 +public:
   1.166 +	enum TMode {EAnalysis,EDeflate};	// mirror CDbStoreCompression enum
   1.167 +public:
   1.168 +	static HDeflateBuf* NewL(MStreamBuf* aHost,CDbStoreCompression::TEncoding& aEncoding,TMode aMode);
   1.169 +private:
   1.170 +	inline HDeflateBuf(MStreamBuf* aHost,CDbStoreCompression::TEncoding& aEncoding,CBufBase* aBuf,TMode aMode);
   1.171 +	virtual inline ~HDeflateBuf();
   1.172 +// from MStreamBuf
   1.173 +	void DoSynchL();
   1.174 +	void DoRelease();
   1.175 +private:
   1.176 +	RWriteStream iHost;
   1.177 +	CDbStoreCompression::TEncoding& iEncoding;
   1.178 +	CBufBase* iBuf;
   1.179 +	TMode iMode;
   1.180 +	};
   1.181 +
   1.182 +NONSHARABLE_CLASS(HInflateBuf) : public TBufBuf
   1.183 +	{
   1.184 +public:
   1.185 +	static HInflateBuf* NewL(MStreamBuf* aHost,const CDbStoreCompression::TEncoding& aEncoding);
   1.186 +private:
   1.187 +	inline HInflateBuf(CBufBase* aBuf);
   1.188 +	virtual inline ~HInflateBuf();
   1.189 +// from MStreamBuf
   1.190 +	void DoRelease();
   1.191 +private:
   1.192 +	CBufBase* iBuf;
   1.193 +	};
   1.194 +
   1.195 +NONSHARABLE_CLASS(CDbStoreTable::CCompressor) : public CBase, public CCluster::MAlter
   1.196 +	{
   1.197 +public:
   1.198 +	inline CCompressor();
   1.199 +	~CCompressor();
   1.200 +	void ProcessL(CDbStoreTable* aTable);
   1.201 +private:
   1.202 +	TUint8* AlterRecordL(TUint8* aWPtr,const TUint8* aRPtr,TInt aLength);
   1.203 +private:
   1.204 +	CDbStoreTable* iTable;
   1.205 +	RDbRow iRow;
   1.206 +	};
   1.207 +
   1.208 +// Class Huffman
   1.209 +//
   1.210 +// This class builds a huffman encoding from a frequency table and builds
   1.211 +// a decoding tree from a code-lengths table
   1.212 +//
   1.213 +// the encoding generated is based on the rule that given two symbols s1 and s2, with 
   1.214 +// code length l1 and l2, and huffman codes h1 and h2:
   1.215 +//
   1.216 +// if l1<l2 then h1<h2 when compared lexicographically
   1.217 +// if l1==l2 and s1<s2 then h1<h2 ditto
   1.218 +//
   1.219 +// This allows the encoding to be stored compactly as a table of code lengths
   1.220 +
   1.221 +//
   1.222 +// recursive function to calculate the code lengths from the node tree
   1.223 +//
   1.224 +void Huffman::Lengths(TUint32* aLengths,const TNode* aNodes,TInt aNode,TInt aLen)
   1.225 +	{
   1.226 +	__ASSERT(aLen<KHuffMaxCodeLength);
   1.227 +	++aLen;
   1.228 +	const TNode& node=aNodes[aNode];
   1.229 +	if (node.iLeft&KLeaf)
   1.230 +		aLengths[node.iLeft&~KLeaf]=aLen;
   1.231 +	else
   1.232 +		Lengths(aLengths,aNodes,node.iLeft,aLen);
   1.233 +	if (node.iRight&KLeaf)
   1.234 +		aLengths[node.iRight&~KLeaf]=aLen;
   1.235 +	else
   1.236 +		Lengths(aLengths,aNodes,node.iRight,aLen);
   1.237 +	}
   1.238 +
   1.239 +//
   1.240 +// write the subtree below aPtr and return the head
   1.241 +//
   1.242 +TUint32* Huffman::SubTree(TUint32* aPtr,const TUint32* aValue,TUint32** aLevel)
   1.243 +	{
   1.244 +	TUint32* l=*aLevel++;
   1.245 +	if (l>aValue)
   1.246 +		{
   1.247 +		TUint32* sub1=SubTree(aPtr,aValue,aLevel);	// 0-tree first
   1.248 +		aPtr=SubTree(sub1,aValue-(aPtr-sub1)-1,aLevel);			// 1-tree
   1.249 +		TInt branch=(TUint8*)sub1-(TUint8*)aPtr;
   1.250 +		*--aPtr=branch;
   1.251 +		}
   1.252 +	else if (l==aValue)
   1.253 +		{
   1.254 +		TUint term0=*aValue--;						// 0-term
   1.255 +		aPtr=SubTree(aPtr,aValue,aLevel);			// 1-tree
   1.256 +		*--aPtr=term0>>16;
   1.257 +		}
   1.258 +	else	// l<iNext
   1.259 +		{
   1.260 +		TUint term0=*aValue--;						// 0-term
   1.261 +		TUint term1=*aValue--;
   1.262 +		*--aPtr=(term1>>16<<16)|(term0>>16);
   1.263 +		}
   1.264 +	return aPtr;
   1.265 +	}
   1.266 +
   1.267 +//
   1.268 +// Build a huffman encoding table from a symbol frequency table
   1.269 +// aTable contains frequency data on input for aCodes symbols
   1.270 +// aTable contains the huffman encoding on output
   1.271 +//
   1.272 +void Huffman::EncodingL(TUint32* aTable,TInt aCodes)
   1.273 +	{
   1.274 +//
   1.275 +// step 1. Sort the values into decreasing order of frequency
   1.276 +//
   1.277 +	TLeaf* leaves=new(ELeave) TLeaf[aCodes];
   1.278 +	CleanupArrayDeletePushL(leaves);
   1.279 +	TInt lCount=0;
   1.280 +	TInt ii;
   1.281 +	for (ii=0;ii<aCodes;++ii)
   1.282 +		{
   1.283 +		TUint c=aTable[ii];
   1.284 +		if (c==0)
   1.285 +			continue;	// no coding for ii
   1.286 +		TInt jj;
   1.287 +		for (jj=0;jj<lCount;++jj)
   1.288 +			{
   1.289 +			if (leaves[jj].iCount<=c)
   1.290 +				break;
   1.291 +			}
   1.292 +		Mem::Move(leaves+jj+1,leaves+jj,sizeof(TLeaf)*(lCount-jj));
   1.293 +		leaves[jj].iCount=c;
   1.294 +		leaves[jj].iVal=THuff(ii|KLeaf);
   1.295 +		lCount++;
   1.296 +		}
   1.297 +//
   1.298 +// Huffman algorithm: pair off least frequent nodes and reorder
   1.299 +// result is the code lengths in aTable[]
   1.300 +//
   1.301 +	if (lCount==1)	// special case for a single value (always encode as "0")
   1.302 +		aTable[leaves[0].iVal&~KLeaf]=1;
   1.303 +	else if (lCount>1)
   1.304 +		{	//	don't encode for empty coding: leaves in order now
   1.305 +		TInt max=0;
   1.306 +		TNode* nodes=new(ELeave) TNode[lCount-1];
   1.307 +		while (--lCount>0)
   1.308 +			{
   1.309 +			TNode& node=nodes[max];
   1.310 +			node.iLeft=leaves[lCount-1].iVal;
   1.311 +			node.iRight=leaves[lCount].iVal;
   1.312 +			// re-order the leaves now to reflect new combined frequency
   1.313 +			TUint c=leaves[lCount-1].iCount+leaves[lCount].iCount;
   1.314 +			TInt jj=lCount;
   1.315 +			while (--jj>0)
   1.316 +				{
   1.317 +				if (leaves[jj-1].iCount>=c)
   1.318 +					break;
   1.319 +				}
   1.320 +			Mem::Move(leaves+jj+1,leaves+jj,sizeof(TLeaf)*(lCount-1-jj));
   1.321 +			// update new leaf
   1.322 +			leaves[jj].iCount=c;
   1.323 +			leaves[jj].iVal=THuff(max);
   1.324 +			max++;
   1.325 +			}
   1.326 +		Lengths(aTable,nodes,leaves[0].iVal,0);
   1.327 +		delete[] nodes;
   1.328 +		}
   1.329 +	CleanupStack::PopAndDestroy();		// leaves
   1.330 +//
   1.331 +// step 3: Generate the coding based on the code lengths
   1.332 +//
   1.333 +	TInt lenCount[KHuffMaxCodeLength];
   1.334 +	Mem::FillZ(lenCount,sizeof(lenCount));
   1.335 +
   1.336 +	for (ii=aCodes;--ii>=0;)
   1.337 +		{
   1.338 +		TInt len=aTable[ii]-1;
   1.339 +		if (len>=0)
   1.340 +			++lenCount[len];
   1.341 +		}
   1.342 +
   1.343 +	TUint nextCode[KHuffMaxCodeLength];
   1.344 +	TUint code=0;
   1.345 +	for (ii=0;ii<KHuffMaxCodeLength;++ii)
   1.346 +		{
   1.347 +		nextCode[ii]=code;
   1.348 +		code=(code+lenCount[ii])<<1;
   1.349 +		}
   1.350 +
   1.351 +	for (ii=0;ii<aCodes;++ii)
   1.352 +		{
   1.353 +		TInt len=aTable[ii];
   1.354 +		if (len)
   1.355 +			{
   1.356 +			aTable[ii] = (nextCode[len-1]<<(KHuffMaxCodeLength-len))|(len<<KHuffMaxCodeLength);
   1.357 +			++nextCode[len-1];
   1.358 +			}
   1.359 +		}
   1.360 +	}
   1.361 +
   1.362 +//
   1.363 +// generate the decoding tree from the huffman code length data
   1.364 +// output alphabet is [aBase,aBase+aCodes)
   1.365 +//
   1.366 +void Huffman::Decoding(TUint32* aDecoding,TInt aCodes,TInt aBase)
   1.367 +	{
   1.368 +	TInt counts[KHuffMaxCodeLength];
   1.369 +	Mem::FillZ(counts,sizeof(counts));
   1.370 +	TInt codes=0;
   1.371 +	TInt ii=aCodes;
   1.372 +	while (--ii>=0)
   1.373 +		{
   1.374 +		TUint len=aDecoding[ii];
   1.375 +		__ASSERT(len<=(TUint)KHuffMaxCodeLength);
   1.376 +		if (len)
   1.377 +			{
   1.378 +			++counts[len-1];
   1.379 +			++codes;
   1.380 +			}
   1.381 +		}
   1.382 +//
   1.383 +	TUint32* level[KHuffMaxCodeLength];
   1.384 +	TUint32* lit=aDecoding+codes;
   1.385 +	for (ii=0;ii<KHuffMaxCodeLength;++ii)
   1.386 +		{
   1.387 +		level[ii]=lit;
   1.388 +		lit-=counts[ii];
   1.389 +		}
   1.390 +	aBase=(aBase<<17)+(KHuffTerminate<<16);
   1.391 +	for (ii=0;ii<aCodes;++ii)
   1.392 +		{
   1.393 +		TUint len=TUint8(aDecoding[ii]);
   1.394 +		if (len)
   1.395 +			*--level[len-1]|=(ii<<17)+aBase;
   1.396 +		}
   1.397 +	if (codes==1)	// codes==1 special case: tree is not complete
   1.398 +		*aDecoding>>=16;	// 0-terminate at root
   1.399 +	else if (codes>1)
   1.400 +		{
   1.401 +		__DEBUG(TUint32* p =)SubTree(aDecoding+codes-1,aDecoding+codes-1,level);
   1.402 +		__ASSERT(p==aDecoding);
   1.403 +		}
   1.404 +	}
   1.405 +
   1.406 +// Class HDeflateHash
   1.407 +
   1.408 +inline HDeflateHash::HDeflateHash()
   1.409 +	{TInt* p=iHash+256;do *--p=-KDeflateMaxDistance-1; while (p>iHash);}
   1.410 +
   1.411 +inline HDeflateHash& HDeflateHash::NewLC(TInt aLinks)
   1.412 +	{
   1.413 +	__ASSERT(!(KDeflateMaxDistance&(KDeflateMaxDistance-1)));	// ensure power of two
   1.414 +	return *new(User::AllocLC(_FOFF(HDeflateHash,iOffset[Min(aLinks,KDeflateMaxDistance)]))) HDeflateHash;
   1.415 +	}
   1.416 +
   1.417 +inline TInt HDeflateHash::Hash(const TUint8* aPtr)
   1.418 +	{
   1.419 +	TUint x=aPtr[0]|(aPtr[1]<<8)|(aPtr[2]<<16);
   1.420 +	return (x*KDeflateHashMultiplier)>>KDeflateHashShift;
   1.421 +	}
   1.422 +
   1.423 +inline TInt HDeflateHash::First(const TUint8* aPtr,TInt aPos)
   1.424 +	{
   1.425 +	TInt h=Hash(aPtr);
   1.426 +	TInt offset=Min(aPos-iHash[h],KDeflateMaxDistance<<1);
   1.427 +	iHash[h]=aPos;
   1.428 +	iOffset[aPos&(KDeflateMaxDistance-1)]=TOffset(offset);
   1.429 +	return offset;
   1.430 +	}
   1.431 +
   1.432 +inline TInt HDeflateHash::Next(TInt aPos,TInt aOffset) const
   1.433 +	{return aOffset+iOffset[(aPos-aOffset)&(KDeflateMaxDistance-1)];}
   1.434 +
   1.435 +
   1.436 +// Class TDeflater
   1.437 +//
   1.438 +// generic deflation algorithm, can do either statistics and the encoder
   1.439 +
   1.440 +TInt MDeflater::Match(const TUint8* aPtr,const TUint8* aEnd,TInt aPos,HDeflateHash& aHash)
   1.441 +	{
   1.442 +	TInt offset=aHash.First(aPtr,aPos);
   1.443 +	if (offset>KDeflateMaxDistance)
   1.444 +		return 0;
   1.445 +	TInt match=0;
   1.446 +	aEnd=Min(aEnd,aPtr+KDeflateMaxLength);
   1.447 +	TUint8 c=*aPtr;
   1.448 +	do
   1.449 +		{
   1.450 +		const TUint8* p=aPtr-offset;
   1.451 +		if (p[match>>16]==c)
   1.452 +			{	// might be a better match
   1.453 +			const TUint8* m=aPtr;
   1.454 +			for (;;)
   1.455 +				{
   1.456 +				if (*p++!=*m++)
   1.457 +					break;
   1.458 +				if (m<aEnd)
   1.459 +					continue;
   1.460 +				return ((m-aPtr)<<16)|offset;
   1.461 +				}
   1.462 +			TInt l=m-aPtr-1;
   1.463 +			if (l>match>>16)
   1.464 +				{
   1.465 +				match=(l<<16)|offset;
   1.466 +				c=m[-1];
   1.467 +				}
   1.468 +			}
   1.469 +		offset=aHash.Next(aPos,offset);
   1.470 +		} while (offset<=KDeflateMaxDistance);
   1.471 +	return match;
   1.472 +	}
   1.473 +
   1.474 +//
   1.475 +// Apply the deflation algorithm to the data [aBase,aEnd)
   1.476 +// Return a pointer after the last byte that was deflated (which may not be aEnd)
   1.477 +//
   1.478 +const TUint8* MDeflater::DoDeflateL(const TUint8* aBase,const TUint8* aEnd,HDeflateHash& aHash)
   1.479 +	{
   1.480 +	__ASSERT(aEnd-aBase>KDeflateMinLength);
   1.481 +//
   1.482 +	const TUint8* ptr=aBase;
   1.483 +#ifdef __EXTRA_DEFLATE
   1.484 +	TInt prev=0;		// the previous deflation match
   1.485 +#endif
   1.486 +	do
   1.487 +		{
   1.488 +		TInt match=Match(ptr,aEnd,ptr-aBase,aHash);
   1.489 +#ifdef __EXTRA_DEFLATE
   1.490 +// Extra deflation applies two optimisations which double the time taken
   1.491 +// 1. If we have a match at p, then test for a better match at p+1 before using it
   1.492 +// 2. When we have a match, add the hash links for all the data which will be skipped 
   1.493 +		if (match>>16 < prev>>16)
   1.494 +			{	// use the previous match--it was better
   1.495 +			TInt len=prev>>16;
   1.496 +			SegmentL(len,prev-(len<<16));
   1.497 +			// fill in missing hash entries for better compression
   1.498 +			const TUint8* e=ptr+len-2;
   1.499 +			do
   1.500 +				{
   1.501 +				++ptr;
   1.502 +				aHash.First(ptr,ptr-aBase);
   1.503 +				} while (ptr<e);
   1.504 +			prev=0;
   1.505 +			}
   1.506 +		else if (match<=(KDeflateMinLength<<16))
   1.507 +			LitLenL(*ptr);			// no deflation match here
   1.508 +		else
   1.509 +			{	// save this match and test the next position
   1.510 +			if (prev)	// we had a match at ptr-1, but this is better
   1.511 +				LitLenL(ptr[-1]);
   1.512 +			prev=match;
   1.513 +			}
   1.514 +		++ptr;
   1.515 +#else
   1.516 +// Basic deflation will store any match found, and not update the hash links for the
   1.517 +// data which is skipped
   1.518 +		if (match<=(KDeflateMinLength<<16))		// no match
   1.519 +			LitLenL(*ptr++);
   1.520 +		else
   1.521 +			{	// store the match
   1.522 +			TInt len=match>>16;
   1.523 +			SegmentL(len,match-(len<<16));
   1.524 +			ptr+=len;
   1.525 +			}
   1.526 +#endif
   1.527 +		} while (ptr+KDeflateMinLength-1<aEnd);
   1.528 +#ifdef __EXTRA_DEFLATE
   1.529 +	if (prev)
   1.530 +		{		// emit the stored match
   1.531 +		TInt len=prev>>16;
   1.532 +		SegmentL(len,prev-(len<<16));
   1.533 +		ptr+=len-1;
   1.534 +		}
   1.535 +#endif
   1.536 +	return ptr;
   1.537 +	}
   1.538 +
   1.539 +//
   1.540 +// The generic deflation algorithm
   1.541 +//
   1.542 +void MDeflater::DeflateL(const TUint8* aBase,TInt aLength)
   1.543 +	{
   1.544 +	const TUint8* end=aBase+aLength;
   1.545 +	if (aLength>KDeflateMinLength)
   1.546 +		{	// deflation kicks in if there is enough data
   1.547 +		HDeflateHash& hash=HDeflateHash::NewLC(aLength);
   1.548 +		aBase=DoDeflateL(aBase,end,hash);
   1.549 +		CleanupStack::PopAndDestroy();
   1.550 +		}
   1.551 +	while (aBase<end)					// emit remaining bytes
   1.552 +		LitLenL(*aBase++);
   1.553 +	LitLenL(CDbStoreCompression::TEncoding::EEos);	// eos marker
   1.554 +	}
   1.555 +
   1.556 +//
   1.557 +// Turn a (length,offset) pair into the deflation codes+extra bits before calling
   1.558 +// the specific LitLen(), Offset() and Extra() functions.
   1.559 +//
   1.560 +void MDeflater::SegmentL(TInt aLength,TInt aDistance)
   1.561 +	{
   1.562 +	__ASSERT(aLength>=KDeflateMinLength && aLength<=KDeflateMaxLength);
   1.563 +	aLength-=KDeflateMinLength;
   1.564 +	TInt extralen=0;
   1.565 +	TUint len=aLength;
   1.566 +	while (len>=8)
   1.567 +		{
   1.568 +		++extralen;
   1.569 +		len>>=1;
   1.570 +		}
   1.571 +	__ASSERT((extralen<<2)+len<CDbStoreCompression::TEncoding::ELengths);
   1.572 +	LitLenL((extralen<<2)+len+CDbStoreCompression::TEncoding::ELiterals);
   1.573 +	if (extralen)
   1.574 +		ExtraL(extralen,TUint(aLength)<<(32-extralen));
   1.575 +//
   1.576 +	__ASSERT(aDistance>0 && aDistance<=KDeflateMaxDistance);
   1.577 +	aDistance--;
   1.578 +	extralen=0;
   1.579 +	TUint dist=aDistance;
   1.580 +	while (dist>=8)
   1.581 +		{
   1.582 +		++extralen;
   1.583 +		dist>>=1;
   1.584 +		}
   1.585 +	__ASSERT((extralen<<2)+dist<CDbStoreCompression::TEncoding::EDistances);
   1.586 +	OffsetL((extralen<<2)+dist);
   1.587 +	if (extralen)
   1.588 +		ExtraL(extralen,TUint(aDistance)<<(32-extralen));
   1.589 +	}
   1.590 +
   1.591 +// Class TDeflateStats
   1.592 +//
   1.593 +// This class analyses the data stream to generate the frequency tables 
   1.594 +// for the deflation algorithm
   1.595 +
   1.596 +inline TDeflateStats::TDeflateStats(CDbStoreCompression::TEncoding& aEncoding)
   1.597 +	:iEncoding(aEncoding)
   1.598 +	{}
   1.599 +
   1.600 +void TDeflateStats::LitLenL(TInt aCode)
   1.601 +	{
   1.602 +	++iEncoding.iLitLen[aCode];
   1.603 +	}
   1.604 +
   1.605 +void TDeflateStats::OffsetL(TInt aCode)
   1.606 +	{
   1.607 +	++iEncoding.iDistance[aCode];
   1.608 +	}
   1.609 +
   1.610 +void TDeflateStats::ExtraL(TInt,TUint)
   1.611 +	{}
   1.612 +
   1.613 +// Class THuffEncoder
   1.614 +//
   1.615 +// This class generates the byte stream of huffman codes, writing them out to the stream
   1.616 +
   1.617 +THuffEncoder::THuffEncoder(RWriteStream& aStream)
   1.618 +	:iStream(aStream),iCode(0),iBits(-8),iWrite(iBuf)
   1.619 +	{}
   1.620 +
   1.621 +//
   1.622 +// Store a huffman code generated by Huffman::EncodingL()
   1.623 +//
   1.624 +void THuffEncoder::EncodeL(TUint32 aHuffCode)
   1.625 +	{
   1.626 +	EncodeL(aHuffCode<<(32-KHuffMaxCodeLength),aHuffCode>>KHuffMaxCodeLength);
   1.627 +	}
   1.628 +
   1.629 +//
   1.630 +// Store aLength bits from the most significant bits of aCode
   1.631 +//
   1.632 +void THuffEncoder::EncodeL(TUint aCode,TInt aLength)
   1.633 +	{
   1.634 +	TInt bits=iBits;
   1.635 +	TUint code=iCode|(aCode>>(bits+8));
   1.636 +	bits+=aLength;
   1.637 +	if (bits>=0)
   1.638 +		{
   1.639 +		TUint8* write=iWrite;
   1.640 +		do
   1.641 +			{
   1.642 +			if (write-EBufSize==iBuf)
   1.643 +				{
   1.644 +				iStream.WriteL(iBuf,EBufSize);
   1.645 +				write=iBuf;
   1.646 +				}
   1.647 +			*write++=TUint8(code>>24);
   1.648 +			code<<=8;
   1.649 +			bits-=8;
   1.650 +			} while (bits>=0);
   1.651 +		iWrite=write;
   1.652 +		}
   1.653 +	iCode=code;
   1.654 +	iBits=bits;
   1.655 +	}
   1.656 +
   1.657 +//
   1.658 +// Terminate the huffman coding. The longest code is always 1111111111
   1.659 +//
   1.660 +void THuffEncoder::CompleteL()
   1.661 +	{
   1.662 +	if (iBits>-8)
   1.663 +		EncodeL(0xffffffffu,-iBits);
   1.664 +	if (iWrite>iBuf)
   1.665 +		iStream.WriteL(iBuf,iWrite-iBuf);
   1.666 +	}
   1.667 +
   1.668 +// Class TDeflater
   1.669 +//
   1.670 +// Extends MDeflater to provide huffman encoding of the output
   1.671 +
   1.672 +//
   1.673 +// construct for encoding
   1.674 +//
   1.675 +inline TDeflater::TDeflater(THuffEncoder& aEncoder,const CDbStoreCompression::TEncoding& aEncoding)
   1.676 +	:iEncoder(aEncoder),iEncoding(aEncoding)
   1.677 +	{}
   1.678 +
   1.679 +void TDeflater::LitLenL(TInt aCode)
   1.680 +	{
   1.681 +	iEncoder.EncodeL(iEncoding.iLitLen[aCode]);
   1.682 +	}
   1.683 +
   1.684 +void TDeflater::OffsetL(TInt aCode)
   1.685 +	{
   1.686 +	iEncoder.EncodeL(iEncoding.iDistance[aCode]);
   1.687 +	}
   1.688 +
   1.689 +void TDeflater::ExtraL(TInt aLen,TUint aBits)
   1.690 +	{
   1.691 +	iEncoder.EncodeL(aBits,aLen);
   1.692 +	}
   1.693 +
   1.694 +// Class TInflater
   1.695 +//
   1.696 +// The inflation algorithm, complete with huffman decoding
   1.697 +
   1.698 +TInflater::TInflater(const TUint8* aIn,const CDbStoreCompression::TEncoding& aEncoding)
   1.699 +	:iIn(aIn),iBits(KBitsInit),iLen(0),iLitLenTree(aEncoding.iLitLen),iDistTree(aEncoding.iDistance)
   1.700 +	{}
   1.701 +
   1.702 +//
   1.703 +// consume all data lag in the history buffer, then decode to fill up the output buffer
   1.704 +//
   1.705 +TInt TInflater::Inflate()
   1.706 +	{
   1.707 +// empty the history buffer into the output
   1.708 +	const TUint8* data=iIn;
   1.709 +	TUint bits=iBits;
   1.710 +	const TUint8* from=iRptr;
   1.711 +	TInt len=iLen;
   1.712 +	TUint8* out=iOut;
   1.713 +	TUint8* const end=out+KDeflateMaxDistance;
   1.714 +	const TUint32* node;
   1.715 +	if (len)
   1.716 +		goto useHistory;
   1.717 +//
   1.718 +	if (bits&KBitsEOF)
   1.719 +		return 0;
   1.720 +//
   1.721 +	node=iLitLenTree;
   1.722 +	while (out<end)
   1.723 +		{
   1.724 +		// get a huffman code
   1.725 +		{
   1.726 +		TUint huff;
   1.727 +		for (;;)
   1.728 +			{
   1.729 +			huff=*node++;
   1.730 +			if ((bits<<=1)&KBitsEmpty)
   1.731 +				bits=*data++|KBitsFull;
   1.732 +			if (bits&KBitsNext)
   1.733 +				{
   1.734 +				if (huff&(KHuffTerminate<<16))
   1.735 +					break;
   1.736 +				}
   1.737 +			else
   1.738 +				{
   1.739 +				if (huff&KHuffTerminate)
   1.740 +					{
   1.741 +					huff<<=16;
   1.742 +					break;
   1.743 +					}
   1.744 +				else
   1.745 +					node=PtrAdd(node,huff);
   1.746 +				}
   1.747 +			}
   1.748 +		TInt val=TInt(huff>>17)-CDbStoreCompression::TEncoding::ELiterals;
   1.749 +		if (val<0)
   1.750 +			{
   1.751 +			*out++=TUint8(val);
   1.752 +			node=iLitLenTree;
   1.753 +			continue;			// another literal/length combo
   1.754 +			}
   1.755 +		if (val==CDbStoreCompression::TEncoding::EEos-CDbStoreCompression::TEncoding::ELiterals)
   1.756 +			{	// eos marker. we're done
   1.757 +			bits=KBitsEOF;
   1.758 +			break;
   1.759 +			}
   1.760 +		// get the extra bits for the code
   1.761 +		TInt code=val&0xff;
   1.762 +		if (code>=8)
   1.763 +			{	// xtra bits
   1.764 +			TInt xtra=(code>>2)-1;
   1.765 +			code-=xtra<<2;
   1.766 +			do
   1.767 +				{
   1.768 +				if ((bits<<=1)&KBitsEmpty)
   1.769 +					bits=*data++|KBitsFull;
   1.770 +				code<<=1;
   1.771 +				if (bits&KBitsNext)
   1.772 +					code|=1;
   1.773 +				} while (--xtra!=0);
   1.774 +			}
   1.775 +		if (val<KDeflateDistCodeBase-CDbStoreCompression::TEncoding::ELiterals)
   1.776 +			{	// length code... get the code
   1.777 +			len=code+KDeflateMinLength;
   1.778 +			__ASSERT(len<=KDeflateMaxLength);
   1.779 +			node=iDistTree;
   1.780 +			continue;			// read the huffman code
   1.781 +			}
   1.782 +		// distance code
   1.783 +		__ASSERT(code<KDeflateMaxDistance);
   1.784 +		from=out-(code+1);
   1.785 +		if (from+KDeflateMaxDistance<end)
   1.786 +			from+=KDeflateMaxDistance;
   1.787 +		}
   1.788 +useHistory:
   1.789 +		TInt tfr=Min(end-out,len);
   1.790 +		len-=tfr;
   1.791 +		do
   1.792 +			{
   1.793 +			*out++=*from++;
   1.794 +			if (from==end)
   1.795 +				from-=KDeflateMaxDistance;
   1.796 +			} while (--tfr!=0);
   1.797 +		node=iLitLenTree;
   1.798 +		};
   1.799 +	iIn=data;
   1.800 +	iBits=bits;
   1.801 +	iRptr=from;
   1.802 +	iLen=len;
   1.803 +	return out-iOut;
   1.804 +	}
   1.805 +
   1.806 +inline const TUint8* TInflater::Ptr() const
   1.807 +	{return iOut;}
   1.808 +inline TInt TInflater::BufferSize()
   1.809 +	{return KDeflateMaxDistance;}
   1.810 +
   1.811 +// Class HDeflateBuf
   1.812 +//
   1.813 +// This stream buffer applies the analysis or deflation and huffman coding
   1.814 +// on the entire stream data when it is committed
   1.815 +
   1.816 +inline HDeflateBuf::HDeflateBuf(MStreamBuf* aHost,CDbStoreCompression::TEncoding& aEncoding,CBufBase* aBuf,TMode aMode)
   1.817 +	:iHost(aHost),iEncoding(aEncoding),iBuf(aBuf),iMode(aMode)
   1.818 +	{Set(*aBuf,0);}
   1.819 +
   1.820 +HDeflateBuf* HDeflateBuf::NewL(MStreamBuf* aHost,CDbStoreCompression::TEncoding& aEncoding,TMode aMode)
   1.821 +	{
   1.822 +	CBufBase* buf=CBufFlat::NewL(512);
   1.823 +	CleanupStack::PushL(buf);
   1.824 +	HDeflateBuf* self=new(ELeave) HDeflateBuf(aHost,aEncoding,buf,aMode);
   1.825 +	CleanupStack::Pop();
   1.826 +	return self;
   1.827 +	}
   1.828 +
   1.829 +inline HDeflateBuf::~HDeflateBuf()
   1.830 +	{delete iBuf;iHost.Release();}
   1.831 +
   1.832 +void HDeflateBuf::DoRelease()
   1.833 +	{
   1.834 +	delete this;
   1.835 +	}
   1.836 +
   1.837 +//
   1.838 +// This is where it all happens
   1.839 +//
   1.840 +void HDeflateBuf::DoSynchL()
   1.841 +	{
   1.842 +	if (iMode==EAnalysis)
   1.843 +		{
   1.844 +		TDeflateStats deflater(iEncoding);
   1.845 +		deflater.DeflateL(iBuf->Ptr(0).Ptr(),iBuf->Size());
   1.846 +		}
   1.847 +	else
   1.848 +		{
   1.849 +		THuffEncoder encoder(iHost);
   1.850 +		TDeflater deflater(encoder,iEncoding);
   1.851 +		deflater.DeflateL(iBuf->Ptr(0).Ptr(),iBuf->Size());
   1.852 +		encoder.CompleteL();
   1.853 +		iHost.CommitL();
   1.854 +		}
   1.855 +	}
   1.856 +
   1.857 +// Class HInflateBuf
   1.858 +//
   1.859 +// Inflate the input stream. This is not a filter, it reads all the input, inflates it and
   1.860 +// keeps it in a memory buffer.
   1.861 +
   1.862 +const TInt KInflateBufSize=0x800;	// 2K
   1.863 +
   1.864 +HInflateBuf::HInflateBuf(CBufBase* aBuf)
   1.865 +	:iBuf(aBuf)
   1.866 +	{
   1.867 +	Set(*aBuf,0,ERead);
   1.868 +	}
   1.869 +
   1.870 +inline HInflateBuf::~HInflateBuf()
   1.871 +	{delete iBuf;}
   1.872 +
   1.873 +void HInflateBuf::DoRelease()
   1.874 +	{
   1.875 +	delete this;
   1.876 +	}
   1.877 +
   1.878 +HInflateBuf* HInflateBuf::NewL(MStreamBuf* aHost,const CDbStoreCompression::TEncoding& aEncoding)
   1.879 +	{
   1.880 +	CBufFlat* host=CBufFlat::NewL(256);
   1.881 +	CleanupStack::PushL(host);
   1.882 +	TUint8 buffer[KInflateBufSize];
   1.883 +	for (;;)
   1.884 +		{
   1.885 +		TInt len=aHost->ReadL(buffer,KInflateBufSize);
   1.886 +		if (len)
   1.887 +			host->InsertL(host->Size(),buffer,len);
   1.888 +		if (len<KInflateBufSize)
   1.889 +			break;
   1.890 +		}
   1.891 +	CBufSeg* out=CBufSeg::NewL(256);
   1.892 +	CleanupStack::PushL(out);
   1.893 +	TInflater* inflater=new(ELeave) TInflater(host->Ptr(0).Ptr(),aEncoding);
   1.894 +	CleanupStack::PushL(inflater);
   1.895 +	for (;;)
   1.896 +		{
   1.897 +		TInt len=inflater->Inflate();
   1.898 +		if (len)
   1.899 +			out->InsertL(out->Size(),inflater->Ptr(),len);
   1.900 +		if (len<inflater->BufferSize())
   1.901 +			break;
   1.902 +		}
   1.903 +	HInflateBuf* buf=new(ELeave) HInflateBuf(out);
   1.904 +	CleanupStack::PopAndDestroy();	// inflater
   1.905 +	CleanupStack::Pop();			// out
   1.906 +	CleanupStack::PopAndDestroy();	// host
   1.907 +	aHost->Release();				// don't need this anymore
   1.908 +	return buf;
   1.909 +	}
   1.910 +
   1.911 +// Class CDbStoreTable::Compressor
   1.912 +//
   1.913 +// This class processes an entire table for analysis or compression, using the
   1.914 +// CDbStoreRecords::AlterL() functionality and call back to ensure that all clusters
   1.915 +// and BLOBs are read and written.
   1.916 +
   1.917 +inline CDbStoreTable::CCompressor::CCompressor()
   1.918 +	{}
   1.919 +
   1.920 +CDbStoreTable::CCompressor::~CCompressor()
   1.921 +	{
   1.922 +	if (iTable)
   1.923 +		iTable->Close();
   1.924 +	iRow.Close();
   1.925 +	}
   1.926 +
   1.927 +//
   1.928 +// Walk through every cluster in the table
   1.929 +//
   1.930 +void CDbStoreTable::CCompressor::ProcessL(CDbStoreTable* aTable)
   1.931 +	{
   1.932 +	iTable=aTable;
   1.933 +	CDbStoreRecords& rec=aTable->StoreRecordsL();
   1.934 +	for (TClusterId cluster=rec.Head();cluster!=KNullClusterId;cluster=rec.AlterL(cluster,*this))
   1.935 +		;
   1.936 +	}
   1.937 +
   1.938 +//
   1.939 +// Compress every blob, and transfer the record from aRPtr to aWPtr
   1.940 +//
   1.941 +TUint8* CDbStoreTable::CCompressor::AlterRecordL(TUint8* aWPtr,const TUint8* aRPtr,TInt aLength)
   1.942 +	{
   1.943 +	if (iTable->Def().Columns().HasLongColumns())
   1.944 +		{
   1.945 +		iTable->CopyToRowL(iRow,TPtrC8(aRPtr,aLength));
   1.946 +		CDbBlobSpace* blobs=iTable->BlobsL();
   1.947 +		TDbColNo col=1;
   1.948 +		HDbColumnSet::TIteratorC iter=iTable->Def().Columns().Begin();
   1.949 +		const HDbColumnSet::TIteratorC end=iTable->Def().Columns().End();
   1.950 +		do
   1.951 +			{
   1.952 +			if (!TDbCol::IsLong(iter->Type()))
   1.953 +				continue;
   1.954 +			TDbBlob& blob=CONST_CAST(TDbBlob&,TDbColumnC(iRow,col).Blob());
   1.955 +			if (blob.IsInline())
   1.956 +				continue;
   1.957 +			// do what has to be done...?
   1.958 +			TUint8* data=(TUint8*)User::AllocLC(blob.Size());
   1.959 +			blobs->ReadLC(blob.Id(),iter->Type())->ReadL(data,blob.Size());
   1.960 +			CleanupStack::PopAndDestroy();	// stream buffer
   1.961 +			// re-write the Blob to compress it
   1.962 +			blobs->DeleteL(blob.Id());
   1.963 +			blob.SetId(blobs->CreateL(iter->Type(),data,blob.Size()));
   1.964 +			CleanupStack::PopAndDestroy();	// data
   1.965 +			} while (++col,++iter<end);
   1.966 +		iTable->CopyFromRow(aWPtr,iRow);
   1.967 +		}
   1.968 +	else
   1.969 +		Mem::Copy(aWPtr,aRPtr,aLength);
   1.970 +	return aWPtr+aLength;
   1.971 +	}
   1.972 +
   1.973 +// Class CDbStoreCompression
   1.974 +//
   1.975 +// This class manages the compression for the database, applying filters as appropriate
   1.976 +// It also defines the extrenalisation format for the huffman trees
   1.977 +
   1.978 +const TInt KDeflationCodes=3*(CDbStoreCompression::TEncoding::ELitLens+CDbStoreCompression::TEncoding::EDistances);
   1.979 +
   1.980 +inline CDbStoreCompression::CDbStoreCompression()
   1.981 +//	:iState(EAnalysis)
   1.982 +	{}
   1.983 +
   1.984 +CDbStoreCompression* CDbStoreCompression::NewL()
   1.985 +	{
   1.986 +	return new(ELeave) CDbStoreCompression;
   1.987 +	}
   1.988 +
   1.989 +//
   1.990 +// Build huffman codings from the freqeuncy tables
   1.991 +//
   1.992 +void CDbStoreCompression::EncodeL()
   1.993 +	{
   1.994 +	__ASSERT(iState==EAnalysis);
   1.995 +	TUint32* p=iEncoding[0].iLitLen;
   1.996 +	TUint32* end=p+KDeflationCodes;
   1.997 +	do
   1.998 +		{
   1.999 +		Huffman::EncodingL(p,TEncoding::ELitLens);
  1.1000 +		p+=TEncoding::ELitLens;
  1.1001 +		Huffman::EncodingL(p,TEncoding::EDistances);
  1.1002 +		p+=TEncoding::EDistances;
  1.1003 +		} while (p<end);
  1.1004 +	iState=EEncoding;
  1.1005 +	}
  1.1006 +
  1.1007 +//
  1.1008 +// Store the encoding tables as a sequence of code lengths
  1.1009 +// The code lengths (0-25) are themselves huffman coded, and the meta coding is stored first
  1.1010 +//
  1.1011 +void CDbStoreCompression::ExternalizeL(RWriteStream& aStream) const
  1.1012 +	{
  1.1013 +	__ASSERT(iState==EEncoding);
  1.1014 +	const TUint32* base=iEncoding[0].iLitLen;
  1.1015 +	const TUint32* end=base+KDeflationCodes;
  1.1016 +	TUint32 codes[KDeflateMetaCodes];
  1.1017 +	Mem::FillZ(codes,sizeof(codes));
  1.1018 +	const TUint32* p=base;
  1.1019 +	do ++codes[*p++>>KHuffMaxCodeLength]; while (p<end);
  1.1020 +	Huffman::EncodingL(codes,KDeflateMetaCodes);
  1.1021 +// save the meta encoding
  1.1022 +	p=codes+KDeflateMetaCodes;
  1.1023 +	do
  1.1024 +		{
  1.1025 +		TUint c0=*--p;
  1.1026 +		TUint c1=*--p;
  1.1027 +		c0>>=KHuffMaxCodeLength;
  1.1028 +		c1>>=KHuffMaxCodeLength;
  1.1029 +		aStream.WriteUint8L((c0<<4)|c1);
  1.1030 +		} while (p>codes);
  1.1031 +// write the encoding
  1.1032 +	THuffEncoder encoder(aStream);
  1.1033 +	p=base;
  1.1034 +	do encoder.EncodeL(codes[*p++>>KHuffMaxCodeLength]); while (p<end);
  1.1035 +	encoder.CompleteL();
  1.1036 +	}
  1.1037 +
  1.1038 +//
  1.1039 +// Internalize a previous saved encoding
  1.1040 +//
  1.1041 +void CDbStoreCompression::InternalizeL(RReadStream& aStream)
  1.1042 +	{
  1.1043 +	__ASSERT(iState!=EEncoding);
  1.1044 +//
  1.1045 +// read the meta encoding
  1.1046 +	TUint32 decode[KDeflateMetaCodes];
  1.1047 +	TUint32* p=decode+KDeflateMetaCodes;
  1.1048 +	do
  1.1049 +		{
  1.1050 +		TUint8 c=aStream.ReadUint8L();
  1.1051 +		*--p=c>>4;
  1.1052 +		*--p=c&0xf;
  1.1053 +		} while (p>decode);
  1.1054 +	Huffman::Decoding(decode,KDeflateMetaCodes);
  1.1055 +// decode the encoding
  1.1056 +	p=iEncoding[0].iLitLen;
  1.1057 +	TUint32* end=p+KDeflationCodes;
  1.1058 +	TUint bits=KBitsInit;
  1.1059 +	do
  1.1060 +		{
  1.1061 +		const TUint32* node=decode;
  1.1062 +		TUint huff;
  1.1063 +		for (;;)
  1.1064 +			{
  1.1065 +			huff=*node++;
  1.1066 +			if ((bits<<=1)&KBitsEmpty)
  1.1067 +				bits=aStream.ReadUint8L()|KBitsFull;
  1.1068 +			if (bits&KBitsNext)
  1.1069 +				{
  1.1070 +				if (huff&(KHuffTerminate<<16))
  1.1071 +					break;
  1.1072 +				}
  1.1073 +			else
  1.1074 +				{
  1.1075 +				if (huff&KHuffTerminate)
  1.1076 +					{
  1.1077 +					huff<<=16;
  1.1078 +					break;
  1.1079 +					}
  1.1080 +				else
  1.1081 +					node=PtrAdd(node,huff);
  1.1082 +				}
  1.1083 +			}
  1.1084 +		*p++=huff>>17;
  1.1085 +		} while (p<end);
  1.1086 +// convert the length tables into huffman decoding trees
  1.1087 +	p=iEncoding[0].iLitLen;
  1.1088 +	do
  1.1089 +		{
  1.1090 +		Huffman::Decoding(p,TEncoding::ELitLens);
  1.1091 +		p+=TEncoding::ELitLens;
  1.1092 +		Huffman::Decoding(p,TEncoding::EDistances,KDeflateDistCodeBase);
  1.1093 +		p+=TEncoding::EDistances;
  1.1094 +		} while (p<end);
  1.1095 +	if (iState==EAnalysis)
  1.1096 +		iState=EDecoding;
  1.1097 +	}
  1.1098 +
  1.1099 +//
  1.1100 +// Apply an inflation filter to a read stream
  1.1101 +//
  1.1102 +MStreamBuf* CDbStoreCompression::FilterL(MStreamBuf* aHost,TUint32,RDbStoreReadStream::TType aType)
  1.1103 +	{
  1.1104 +	if (iState==EDecoding || iState==EInflating)
  1.1105 +		return HInflateBuf::NewL(aHost,iEncoding[aType]);
  1.1106 +	return aHost;
  1.1107 +	}
  1.1108 +
  1.1109 +//
  1.1110 +// Apply a statistics or inflation filter to a write stream
  1.1111 +//
  1.1112 +MStreamBuf* CDbStoreCompression::FilterL(MStreamBuf* aHost,TUint32,RDbStoreWriteStream::TType aType)
  1.1113 +	{
  1.1114 +	TState s=iState;
  1.1115 +	if (s==EDecoding)
  1.1116 +		__LEAVE(KErrWrite);		// read-only database
  1.1117 +	else if (s!=EInflating)
  1.1118 +		{
  1.1119 +		__ASSERT(TInt(EAnalysis)==TInt(HDeflateBuf::EAnalysis));
  1.1120 +		__ASSERT(TInt(EEncoding)==TInt(HDeflateBuf::EDeflate));
  1.1121 +		return HDeflateBuf::NewL(aHost,iEncoding[aType],HDeflateBuf::TMode(s));
  1.1122 +		}
  1.1123 +	return aHost;
  1.1124 +	}
  1.1125 +
  1.1126 +// Class CDbStoreDatabase
  1.1127 +//
  1.1128 +// Compression related code is maintained in this source file
  1.1129 +
  1.1130 +//
  1.1131 +// Iterate across all tables applying analysis or compression to them
  1.1132 +//
  1.1133 +void CDbStoreDatabase::CompressTablesL()
  1.1134 +	{
  1.1135 +	TSglQueIterC<CDbStoreDef> iter(SchemaL());
  1.1136 +	const CDbStoreDef* def;
  1.1137 +	while ((def=iter++)!=0)
  1.1138 +		{
  1.1139 +		CDbStoreTable::CCompressor* comp=new(ELeave) CDbStoreTable::CCompressor;
  1.1140 +		CleanupStack::PushL(comp);
  1.1141 +		comp->ProcessL(STATIC_CAST(CDbStoreTable*,TableL(*def)));
  1.1142 +		CleanupStack::PopAndDestroy();	// comp
  1.1143 +		}
  1.1144 +	}
  1.1145 +
  1.1146 +//
  1.1147 +// Compress or decompress the whole database
  1.1148 +//
  1.1149 +void CDbStoreDatabase::CompressL(TStreamId aStreamId,TZipType aZip)
  1.1150 +	{
  1.1151 +	__ASSERT(iStore);
  1.1152 +	iSchemaId=aStreamId;
  1.1153 +// read the databse header for encryption information
  1.1154 +	RStoreReadStream strm;
  1.1155 +	strm.OpenLC(Store(),aStreamId);
  1.1156 +	ReadHeaderL(strm);
  1.1157 +	CleanupStack::PopAndDestroy();	// strm
  1.1158 +	InitPagePoolL();
  1.1159 +//
  1.1160 +	if (iVersion==EDbStoreCompressed)
  1.1161 +		{
  1.1162 +		iCompression->Inflate();
  1.1163 +		if (aZip==EDeflate)
  1.1164 +			__LEAVE(KErrArgument);		// already compressed
  1.1165 +		}
  1.1166 +	else if (aZip==EInflate)
  1.1167 +		__LEAVE(KErrArgument);		// not compressed
  1.1168 +	else
  1.1169 +		{	// deflate pass #1: analyse the database
  1.1170 +		CompressionL();				// construct the compression filter
  1.1171 +		Transaction().DDLBeginLC();
  1.1172 +		CompressTablesL();
  1.1173 +		iClusterCache->FlushL();		// force through the stats buffer
  1.1174 +		ReplaceSchemaL();				// force through the stats buffer
  1.1175 +		CleanupStack::PopAndDestroy();	// rollback after analysis!
  1.1176 +		iCompression->EncodeL();
  1.1177 +		}
  1.1178 +// now inflate or deflate the data
  1.1179 +	Transaction().DDLBeginLC();
  1.1180 +	CompressTablesL();
  1.1181 +	iVersion=TUint8(aZip==EDeflate ? EDbStoreCompressed : EDbStoreVersion2);
  1.1182 +	Transaction().DDLCommitL();
  1.1183 +	CleanupStack::Pop();		// rollback not required
  1.1184 +	}
  1.1185 +
  1.1186 +void CDbStoreDatabase::CompressL(CStreamStore* aStore,TStreamId aStreamId,TZipType aZip)
  1.1187 +	{
  1.1188 +	CDbStoreDatabase* self=NewLC(aStore);
  1.1189 +	CDbObject* db=self->InterfaceL();	// a reference to the database is required
  1.1190 +	CleanupStack::Pop();	// self
  1.1191 +	db->PushL();
  1.1192 +	self->Transaction().DDLPrepareL(*db);
  1.1193 +	self->CompressL(aStreamId,aZip);
  1.1194 +	CleanupStack::PopAndDestroy();	// db
  1.1195 +	}
  1.1196 +
  1.1197 +// Class RDbStoreDatabase
  1.1198 +
  1.1199 +EXPORT_C void RDbStoreDatabase::CompressL(CStreamStore& aStore,TStreamId aId)
  1.1200 +	{
  1.1201 +	CDbStoreDatabase::CompressL(&aStore,aId,CDbStoreDatabase::EDeflate);
  1.1202 +	}
  1.1203 +
  1.1204 +EXPORT_C void RDbStoreDatabase::DecompressL(CStreamStore& aStore,TStreamId aId)
  1.1205 +	{
  1.1206 +	CDbStoreDatabase::CompressL(&aStore,aId,CDbStoreDatabase::EInflate);
  1.1207 +	}