os/persistentdata/persistentstorage/dbms/pcdbms/ustor/US_COMP.CPP
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
sl@0
     1
// Copyright (c) 1998-2009 Nokia Corporation and/or its subsidiary(-ies).
sl@0
     2
// All rights reserved.
sl@0
     3
// This component and the accompanying materials are made available
sl@0
     4
// under the terms of "Eclipse Public License v1.0"
sl@0
     5
// which accompanies this distribution, and is available
sl@0
     6
// at the URL "http://www.eclipse.org/legal/epl-v10.html".
sl@0
     7
//
sl@0
     8
// Initial Contributors:
sl@0
     9
// Nokia Corporation - initial contribution.
sl@0
    10
//
sl@0
    11
// Contributors:
sl@0
    12
//
sl@0
    13
// Description:
sl@0
    14
// Store database compression code
sl@0
    15
// 
sl@0
    16
//
sl@0
    17
sl@0
    18
#include "US_STD.H"
sl@0
    19
#include <s32mem.h>
sl@0
    20
#include "U32STD_DBMS.H"
sl@0
    21
sl@0
    22
#ifdef __WINS__
sl@0
    23
#define __EXTRA_DEFLATE
sl@0
    24
#endif
sl@0
    25
sl@0
    26
// deflation constants
sl@0
    27
const TInt KDeflateMinLength=3;
sl@0
    28
const TInt KDeflateMaxLength=258;
sl@0
    29
const TInt KDeflateMaxDistance=4096;
sl@0
    30
const TInt KDeflateDistCodeBase=0x200;
sl@0
    31
// huffman coding/decoding
sl@0
    32
const TInt KHuffMaxCodeLength=25;
sl@0
    33
const TInt KHuffTerminate=1;
sl@0
    34
const TUint KBitsEmpty=0x80000000u;
sl@0
    35
const TUint KBitsInit=KBitsEmpty>>1;
sl@0
    36
const TUint KBitsFull=KBitsEmpty>>8;
sl@0
    37
const TUint KBitsEOF=KBitsEmpty>>9;
sl@0
    38
const TUint KBitsNext=0x80u;
sl@0
    39
// encoding storage
sl@0
    40
const TInt KDeflateMetaCodes=26;
sl@0
    41
// hashing
sl@0
    42
const TUint KDeflateHashMultiplier=0xAC4B9B19u;
sl@0
    43
const TInt KDeflateHashShift=24;
sl@0
    44
sl@0
    45
class Huffman
sl@0
    46
	{
sl@0
    47
public:
sl@0
    48
	static void EncodingL(TUint32* aEncoding,TInt aCodes);
sl@0
    49
	static void Decoding(TUint32* aDecoding,TInt aCodes,TInt aBase=0);
sl@0
    50
private:
sl@0
    51
	typedef TUint16 THuff;
sl@0
    52
	enum {KLeaf=0x8000};
sl@0
    53
	struct TNode
sl@0
    54
		{
sl@0
    55
		THuff iLeft;
sl@0
    56
		THuff iRight;
sl@0
    57
		};
sl@0
    58
	struct TLeaf
sl@0
    59
		{
sl@0
    60
		TUint iCount;
sl@0
    61
		THuff iVal;
sl@0
    62
		};
sl@0
    63
private:
sl@0
    64
	static void Lengths(TUint32* aLengths,const TNode* aNodes,TInt aNode,TInt aLen);
sl@0
    65
	static TUint32* SubTree(TUint32* aPtr,const TUint32* aValue,TUint32** aLevel);
sl@0
    66
	};
sl@0
    67
sl@0
    68
class THuffEncoder
sl@0
    69
	{
sl@0
    70
public:
sl@0
    71
	THuffEncoder(RWriteStream& aStream);
sl@0
    72
//
sl@0
    73
	void EncodeL(TUint aCode,TInt aLength);
sl@0
    74
	void EncodeL(TUint32 aHuffCode);
sl@0
    75
	void CompleteL();
sl@0
    76
private:
sl@0
    77
	enum {EBufSize=0x100};
sl@0
    78
private:
sl@0
    79
	TUint8 iBuf[EBufSize];
sl@0
    80
	RWriteStream& iStream;
sl@0
    81
	TUint32 iCode;		// code in production
sl@0
    82
	TInt iBits;
sl@0
    83
	TUint8* iWrite;
sl@0
    84
	};
sl@0
    85
sl@0
    86
class HDeflateHash
sl@0
    87
	{
sl@0
    88
public:
sl@0
    89
	inline static HDeflateHash& NewLC(TInt aLinks);
sl@0
    90
//
sl@0
    91
	inline TInt First(const TUint8* aPtr,TInt aPos);
sl@0
    92
	inline TInt Next(TInt aPos,TInt aOffset) const;
sl@0
    93
private:
sl@0
    94
	inline HDeflateHash();
sl@0
    95
	inline static TInt Hash(const TUint8* aPtr);
sl@0
    96
private:
sl@0
    97
	typedef TUint16 TOffset;
sl@0
    98
private:
sl@0
    99
	TInt iHash[256];
sl@0
   100
	TOffset iOffset[1];	// or more
sl@0
   101
	};
sl@0
   102
sl@0
   103
class MDeflater
sl@0
   104
	{
sl@0
   105
public:
sl@0
   106
	void DeflateL(const TUint8* aBase,TInt aLength);
sl@0
   107
private:
sl@0
   108
	const TUint8* DoDeflateL(const TUint8* aBase,const TUint8* aEnd,HDeflateHash& aHash);
sl@0
   109
	static TInt Match(const TUint8* aPtr,const TUint8* aEnd,TInt aPos,HDeflateHash& aHas);
sl@0
   110
	void SegmentL(TInt aLength,TInt aDistance);
sl@0
   111
	virtual void LitLenL(TInt aCode) =0;
sl@0
   112
	virtual void OffsetL(TInt aCode) =0;
sl@0
   113
	virtual void ExtraL(TInt aLen,TUint aBits) =0;
sl@0
   114
	};
sl@0
   115
sl@0
   116
class TInflater
sl@0
   117
	{
sl@0
   118
public:
sl@0
   119
	TInflater(const TUint8* aIn,const CDbStoreCompression::TEncoding& aDecoding);
sl@0
   120
	TInt Inflate();
sl@0
   121
	inline const TUint8* Ptr() const;
sl@0
   122
	inline static TInt BufferSize();
sl@0
   123
private:
sl@0
   124
	const TUint8* iIn;
sl@0
   125
	TUint iBits;
sl@0
   126
	const TUint8* iRptr;			// partial segment
sl@0
   127
	TInt iLen;
sl@0
   128
	const TUint32* iLitLenTree;
sl@0
   129
	const TUint32* iDistTree;
sl@0
   130
	TUint8 iOut[KDeflateMaxDistance];	// circular buffer for distance matches
sl@0
   131
	};
sl@0
   132
sl@0
   133
NONSHARABLE_CLASS(TDeflateStats) : public MDeflater
sl@0
   134
	{
sl@0
   135
public:
sl@0
   136
	inline TDeflateStats(CDbStoreCompression::TEncoding& aEncoding);
sl@0
   137
private:
sl@0
   138
// from MDeflater
sl@0
   139
	void LitLenL(TInt aCode);
sl@0
   140
	void OffsetL(TInt aCode);
sl@0
   141
	void ExtraL(TInt aLen,TUint aBits);
sl@0
   142
private:
sl@0
   143
	CDbStoreCompression::TEncoding& iEncoding;
sl@0
   144
	};
sl@0
   145
sl@0
   146
NONSHARABLE_CLASS(TDeflater) : public MDeflater
sl@0
   147
	{
sl@0
   148
public:
sl@0
   149
	inline TDeflater(THuffEncoder& aEncoder,const CDbStoreCompression::TEncoding& aEncoding);
sl@0
   150
private:
sl@0
   151
// from MDeflater
sl@0
   152
	void LitLenL(TInt aCode);
sl@0
   153
	void OffsetL(TInt aCode);
sl@0
   154
	void ExtraL(TInt aLen,TUint aBits);
sl@0
   155
private:
sl@0
   156
	THuffEncoder& iEncoder;
sl@0
   157
	const CDbStoreCompression::TEncoding& iEncoding;
sl@0
   158
	};
sl@0
   159
sl@0
   160
NONSHARABLE_CLASS(HDeflateBuf) : public TBufBuf
sl@0
   161
	{
sl@0
   162
public:
sl@0
   163
	enum TMode {EAnalysis,EDeflate};	// mirror CDbStoreCompression enum
sl@0
   164
public:
sl@0
   165
	static HDeflateBuf* NewL(MStreamBuf* aHost,CDbStoreCompression::TEncoding& aEncoding,TMode aMode);
sl@0
   166
private:
sl@0
   167
	inline HDeflateBuf(MStreamBuf* aHost,CDbStoreCompression::TEncoding& aEncoding,CBufBase* aBuf,TMode aMode);
sl@0
   168
	virtual inline ~HDeflateBuf();
sl@0
   169
// from MStreamBuf
sl@0
   170
	void DoSynchL();
sl@0
   171
	void DoRelease();
sl@0
   172
private:
sl@0
   173
	RWriteStream iHost;
sl@0
   174
	CDbStoreCompression::TEncoding& iEncoding;
sl@0
   175
	CBufBase* iBuf;
sl@0
   176
	TMode iMode;
sl@0
   177
	};
sl@0
   178
sl@0
   179
NONSHARABLE_CLASS(HInflateBuf) : public TBufBuf
sl@0
   180
	{
sl@0
   181
public:
sl@0
   182
	static HInflateBuf* NewL(MStreamBuf* aHost,const CDbStoreCompression::TEncoding& aEncoding);
sl@0
   183
private:
sl@0
   184
	inline HInflateBuf(CBufBase* aBuf);
sl@0
   185
	virtual inline ~HInflateBuf();
sl@0
   186
// from MStreamBuf
sl@0
   187
	void DoRelease();
sl@0
   188
private:
sl@0
   189
	CBufBase* iBuf;
sl@0
   190
	};
sl@0
   191
sl@0
   192
NONSHARABLE_CLASS(CDbStoreTable::CCompressor) : public CBase, public CCluster::MAlter
sl@0
   193
	{
sl@0
   194
public:
sl@0
   195
	inline CCompressor();
sl@0
   196
	~CCompressor();
sl@0
   197
	void ProcessL(CDbStoreTable* aTable);
sl@0
   198
private:
sl@0
   199
	TUint8* AlterRecordL(TUint8* aWPtr,const TUint8* aRPtr,TInt aLength);
sl@0
   200
private:
sl@0
   201
	CDbStoreTable* iTable;
sl@0
   202
	RDbRow iRow;
sl@0
   203
	};
sl@0
   204
sl@0
   205
// Class Huffman
sl@0
   206
//
sl@0
   207
// This class builds a huffman encoding from a frequency table and builds
sl@0
   208
// a decoding tree from a code-lengths table
sl@0
   209
//
sl@0
   210
// the encoding generated is based on the rule that given two symbols s1 and s2, with 
sl@0
   211
// code length l1 and l2, and huffman codes h1 and h2:
sl@0
   212
//
sl@0
   213
// if l1<l2 then h1<h2 when compared lexicographically
sl@0
   214
// if l1==l2 and s1<s2 then h1<h2 ditto
sl@0
   215
//
sl@0
   216
// This allows the encoding to be stored compactly as a table of code lengths
sl@0
   217
sl@0
   218
//
sl@0
   219
// recursive function to calculate the code lengths from the node tree
sl@0
   220
//
sl@0
   221
void Huffman::Lengths(TUint32* aLengths,const TNode* aNodes,TInt aNode,TInt aLen)
sl@0
   222
	{
sl@0
   223
	__ASSERT(aLen<KHuffMaxCodeLength);
sl@0
   224
	++aLen;
sl@0
   225
	const TNode& node=aNodes[aNode];
sl@0
   226
	if (node.iLeft&KLeaf)
sl@0
   227
		aLengths[node.iLeft&~KLeaf]=aLen;
sl@0
   228
	else
sl@0
   229
		Lengths(aLengths,aNodes,node.iLeft,aLen);
sl@0
   230
	if (node.iRight&KLeaf)
sl@0
   231
		aLengths[node.iRight&~KLeaf]=aLen;
sl@0
   232
	else
sl@0
   233
		Lengths(aLengths,aNodes,node.iRight,aLen);
sl@0
   234
	}
sl@0
   235
sl@0
   236
//
sl@0
   237
// write the subtree below aPtr and return the head
sl@0
   238
//
sl@0
   239
TUint32* Huffman::SubTree(TUint32* aPtr,const TUint32* aValue,TUint32** aLevel)
sl@0
   240
	{
sl@0
   241
	TUint32* l=*aLevel++;
sl@0
   242
	if (l>aValue)
sl@0
   243
		{
sl@0
   244
		TUint32* sub1=SubTree(aPtr,aValue,aLevel);	// 0-tree first
sl@0
   245
		aPtr=SubTree(sub1,aValue-(aPtr-sub1)-1,aLevel);			// 1-tree
sl@0
   246
		TInt branch=(TUint8*)sub1-(TUint8*)aPtr;
sl@0
   247
		*--aPtr=branch;
sl@0
   248
		}
sl@0
   249
	else if (l==aValue)
sl@0
   250
		{
sl@0
   251
		TUint term0=*aValue--;						// 0-term
sl@0
   252
		aPtr=SubTree(aPtr,aValue,aLevel);			// 1-tree
sl@0
   253
		*--aPtr=term0>>16;
sl@0
   254
		}
sl@0
   255
	else	// l<iNext
sl@0
   256
		{
sl@0
   257
		TUint term0=*aValue--;						// 0-term
sl@0
   258
		TUint term1=*aValue--;
sl@0
   259
		*--aPtr=(term1>>16<<16)|(term0>>16);
sl@0
   260
		}
sl@0
   261
	return aPtr;
sl@0
   262
	}
sl@0
   263
sl@0
   264
//
sl@0
   265
// Build a huffman encoding table from a symbol frequency table
sl@0
   266
// aTable contains frequency data on input for aCodes symbols
sl@0
   267
// aTable contains the huffman encoding on output
sl@0
   268
//
sl@0
   269
void Huffman::EncodingL(TUint32* aTable,TInt aCodes)
sl@0
   270
	{
sl@0
   271
//
sl@0
   272
// step 1. Sort the values into decreasing order of frequency
sl@0
   273
//
sl@0
   274
	TLeaf* leaves=new(ELeave) TLeaf[aCodes];
sl@0
   275
	CleanupArrayDeletePushL(leaves);
sl@0
   276
	TInt lCount=0;
sl@0
   277
	TInt ii;
sl@0
   278
	for (ii=0;ii<aCodes;++ii)
sl@0
   279
		{
sl@0
   280
		TUint c=aTable[ii];
sl@0
   281
		if (c==0)
sl@0
   282
			continue;	// no coding for ii
sl@0
   283
		TInt jj;
sl@0
   284
		for (jj=0;jj<lCount;++jj)
sl@0
   285
			{
sl@0
   286
			if (leaves[jj].iCount<=c)
sl@0
   287
				break;
sl@0
   288
			}
sl@0
   289
		Mem::Move(leaves+jj+1,leaves+jj,sizeof(TLeaf)*(lCount-jj));
sl@0
   290
		leaves[jj].iCount=c;
sl@0
   291
		leaves[jj].iVal=THuff(ii|KLeaf);
sl@0
   292
		lCount++;
sl@0
   293
		}
sl@0
   294
//
sl@0
   295
// Huffman algorithm: pair off least frequent nodes and reorder
sl@0
   296
// result is the code lengths in aTable[]
sl@0
   297
//
sl@0
   298
	if (lCount==1)	// special case for a single value (always encode as "0")
sl@0
   299
		aTable[leaves[0].iVal&~KLeaf]=1;
sl@0
   300
	else if (lCount>1)
sl@0
   301
		{	//	don't encode for empty coding: leaves in order now
sl@0
   302
		TInt max=0;
sl@0
   303
		TNode* nodes=new(ELeave) TNode[lCount-1];
sl@0
   304
		while (--lCount>0)
sl@0
   305
			{
sl@0
   306
			TNode& node=nodes[max];
sl@0
   307
			node.iLeft=leaves[lCount-1].iVal;
sl@0
   308
			node.iRight=leaves[lCount].iVal;
sl@0
   309
			// re-order the leaves now to reflect new combined frequency
sl@0
   310
			TUint c=leaves[lCount-1].iCount+leaves[lCount].iCount;
sl@0
   311
			TInt jj=lCount;
sl@0
   312
			while (--jj>0)
sl@0
   313
				{
sl@0
   314
				if (leaves[jj-1].iCount>=c)
sl@0
   315
					break;
sl@0
   316
				}
sl@0
   317
			Mem::Move(leaves+jj+1,leaves+jj,sizeof(TLeaf)*(lCount-1-jj));
sl@0
   318
			// update new leaf
sl@0
   319
			leaves[jj].iCount=c;
sl@0
   320
			leaves[jj].iVal=THuff(max);
sl@0
   321
			max++;
sl@0
   322
			}
sl@0
   323
		Lengths(aTable,nodes,leaves[0].iVal,0);
sl@0
   324
		delete[] nodes;
sl@0
   325
		}
sl@0
   326
	CleanupStack::PopAndDestroy();		// leaves
sl@0
   327
//
sl@0
   328
// step 3: Generate the coding based on the code lengths
sl@0
   329
//
sl@0
   330
	TInt lenCount[KHuffMaxCodeLength];
sl@0
   331
	Mem::FillZ(lenCount,sizeof(lenCount));
sl@0
   332
sl@0
   333
	for (ii=aCodes;--ii>=0;)
sl@0
   334
		{
sl@0
   335
		TInt len=aTable[ii]-1;
sl@0
   336
		if (len>=0)
sl@0
   337
			++lenCount[len];
sl@0
   338
		}
sl@0
   339
sl@0
   340
	TUint nextCode[KHuffMaxCodeLength];
sl@0
   341
	TUint code=0;
sl@0
   342
	for (ii=0;ii<KHuffMaxCodeLength;++ii)
sl@0
   343
		{
sl@0
   344
		nextCode[ii]=code;
sl@0
   345
		code=(code+lenCount[ii])<<1;
sl@0
   346
		}
sl@0
   347
sl@0
   348
	for (ii=0;ii<aCodes;++ii)
sl@0
   349
		{
sl@0
   350
		TInt len=aTable[ii];
sl@0
   351
		if (len)
sl@0
   352
			{
sl@0
   353
			aTable[ii] = (nextCode[len-1]<<(KHuffMaxCodeLength-len))|(len<<KHuffMaxCodeLength);
sl@0
   354
			++nextCode[len-1];
sl@0
   355
			}
sl@0
   356
		}
sl@0
   357
	}
sl@0
   358
sl@0
   359
//
sl@0
   360
// generate the decoding tree from the huffman code length data
sl@0
   361
// output alphabet is [aBase,aBase+aCodes)
sl@0
   362
//
sl@0
   363
void Huffman::Decoding(TUint32* aDecoding,TInt aCodes,TInt aBase)
sl@0
   364
	{
sl@0
   365
	TInt counts[KHuffMaxCodeLength];
sl@0
   366
	Mem::FillZ(counts,sizeof(counts));
sl@0
   367
	TInt codes=0;
sl@0
   368
	TInt ii=aCodes;
sl@0
   369
	while (--ii>=0)
sl@0
   370
		{
sl@0
   371
		TUint len=aDecoding[ii];
sl@0
   372
		__ASSERT(len<=(TUint)KHuffMaxCodeLength);
sl@0
   373
		if (len)
sl@0
   374
			{
sl@0
   375
			++counts[len-1];
sl@0
   376
			++codes;
sl@0
   377
			}
sl@0
   378
		}
sl@0
   379
//
sl@0
   380
	TUint32* level[KHuffMaxCodeLength];
sl@0
   381
	TUint32* lit=aDecoding+codes;
sl@0
   382
	for (ii=0;ii<KHuffMaxCodeLength;++ii)
sl@0
   383
		{
sl@0
   384
		level[ii]=lit;
sl@0
   385
		lit-=counts[ii];
sl@0
   386
		}
sl@0
   387
	aBase=(aBase<<17)+(KHuffTerminate<<16);
sl@0
   388
	for (ii=0;ii<aCodes;++ii)
sl@0
   389
		{
sl@0
   390
		TUint len=TUint8(aDecoding[ii]);
sl@0
   391
		if (len)
sl@0
   392
			*--level[len-1]|=(ii<<17)+aBase;
sl@0
   393
		}
sl@0
   394
	if (codes==1)	// codes==1 special case: tree is not complete
sl@0
   395
		*aDecoding>>=16;	// 0-terminate at root
sl@0
   396
	else if (codes>1)
sl@0
   397
		{
sl@0
   398
		__DEBUG(TUint32* p =)SubTree(aDecoding+codes-1,aDecoding+codes-1,level);
sl@0
   399
		__ASSERT(p==aDecoding);
sl@0
   400
		}
sl@0
   401
	}
sl@0
   402
sl@0
   403
// Class HDeflateHash
sl@0
   404
sl@0
   405
inline HDeflateHash::HDeflateHash()
sl@0
   406
	{TInt* p=iHash+256;do *--p=-KDeflateMaxDistance-1; while (p>iHash);}
sl@0
   407
sl@0
   408
inline HDeflateHash& HDeflateHash::NewLC(TInt aLinks)
sl@0
   409
	{
sl@0
   410
	__ASSERT(!(KDeflateMaxDistance&(KDeflateMaxDistance-1)));	// ensure power of two
sl@0
   411
	return *new(User::AllocLC(_FOFF(HDeflateHash,iOffset[Min(aLinks,KDeflateMaxDistance)]))) HDeflateHash;
sl@0
   412
	}
sl@0
   413
sl@0
   414
inline TInt HDeflateHash::Hash(const TUint8* aPtr)
sl@0
   415
	{
sl@0
   416
	TUint x=aPtr[0]|(aPtr[1]<<8)|(aPtr[2]<<16);
sl@0
   417
	return (x*KDeflateHashMultiplier)>>KDeflateHashShift;
sl@0
   418
	}
sl@0
   419
sl@0
   420
inline TInt HDeflateHash::First(const TUint8* aPtr,TInt aPos)
sl@0
   421
	{
sl@0
   422
	TInt h=Hash(aPtr);
sl@0
   423
	TInt offset=Min(aPos-iHash[h],KDeflateMaxDistance<<1);
sl@0
   424
	iHash[h]=aPos;
sl@0
   425
	iOffset[aPos&(KDeflateMaxDistance-1)]=TOffset(offset);
sl@0
   426
	return offset;
sl@0
   427
	}
sl@0
   428
sl@0
   429
inline TInt HDeflateHash::Next(TInt aPos,TInt aOffset) const
sl@0
   430
	{return aOffset+iOffset[(aPos-aOffset)&(KDeflateMaxDistance-1)];}
sl@0
   431
sl@0
   432
sl@0
   433
// Class TDeflater
sl@0
   434
//
sl@0
   435
// generic deflation algorithm, can do either statistics and the encoder
sl@0
   436
sl@0
   437
TInt MDeflater::Match(const TUint8* aPtr,const TUint8* aEnd,TInt aPos,HDeflateHash& aHash)
sl@0
   438
	{
sl@0
   439
	TInt offset=aHash.First(aPtr,aPos);
sl@0
   440
	if (offset>KDeflateMaxDistance)
sl@0
   441
		return 0;
sl@0
   442
	TInt match=0;
sl@0
   443
	aEnd=Min(aEnd,aPtr+KDeflateMaxLength);
sl@0
   444
	TUint8 c=*aPtr;
sl@0
   445
	do
sl@0
   446
		{
sl@0
   447
		const TUint8* p=aPtr-offset;
sl@0
   448
		if (p[match>>16]==c)
sl@0
   449
			{	// might be a better match
sl@0
   450
			const TUint8* m=aPtr;
sl@0
   451
			for (;;)
sl@0
   452
				{
sl@0
   453
				if (*p++!=*m++)
sl@0
   454
					break;
sl@0
   455
				if (m<aEnd)
sl@0
   456
					continue;
sl@0
   457
				return ((m-aPtr)<<16)|offset;
sl@0
   458
				}
sl@0
   459
			TInt l=m-aPtr-1;
sl@0
   460
			if (l>match>>16)
sl@0
   461
				{
sl@0
   462
				match=(l<<16)|offset;
sl@0
   463
				c=m[-1];
sl@0
   464
				}
sl@0
   465
			}
sl@0
   466
		offset=aHash.Next(aPos,offset);
sl@0
   467
		} while (offset<=KDeflateMaxDistance);
sl@0
   468
	return match;
sl@0
   469
	}
sl@0
   470
sl@0
   471
//
sl@0
   472
// Apply the deflation algorithm to the data [aBase,aEnd)
sl@0
   473
// Return a pointer after the last byte that was deflated (which may not be aEnd)
sl@0
   474
//
sl@0
   475
const TUint8* MDeflater::DoDeflateL(const TUint8* aBase,const TUint8* aEnd,HDeflateHash& aHash)
sl@0
   476
	{
sl@0
   477
	__ASSERT(aEnd-aBase>KDeflateMinLength);
sl@0
   478
//
sl@0
   479
	const TUint8* ptr=aBase;
sl@0
   480
#ifdef __EXTRA_DEFLATE
sl@0
   481
	TInt prev=0;		// the previous deflation match
sl@0
   482
#endif
sl@0
   483
	do
sl@0
   484
		{
sl@0
   485
		TInt match=Match(ptr,aEnd,ptr-aBase,aHash);
sl@0
   486
#ifdef __EXTRA_DEFLATE
sl@0
   487
// Extra deflation applies two optimisations which double the time taken
sl@0
   488
// 1. If we have a match at p, then test for a better match at p+1 before using it
sl@0
   489
// 2. When we have a match, add the hash links for all the data which will be skipped 
sl@0
   490
		if (match>>16 < prev>>16)
sl@0
   491
			{	// use the previous match--it was better
sl@0
   492
			TInt len=prev>>16;
sl@0
   493
			SegmentL(len,prev-(len<<16));
sl@0
   494
			// fill in missing hash entries for better compression
sl@0
   495
			const TUint8* e=ptr+len-2;
sl@0
   496
			do
sl@0
   497
				{
sl@0
   498
				++ptr;
sl@0
   499
				aHash.First(ptr,ptr-aBase);
sl@0
   500
				} while (ptr<e);
sl@0
   501
			prev=0;
sl@0
   502
			}
sl@0
   503
		else if (match<=(KDeflateMinLength<<16))
sl@0
   504
			LitLenL(*ptr);			// no deflation match here
sl@0
   505
		else
sl@0
   506
			{	// save this match and test the next position
sl@0
   507
			if (prev)	// we had a match at ptr-1, but this is better
sl@0
   508
				LitLenL(ptr[-1]);
sl@0
   509
			prev=match;
sl@0
   510
			}
sl@0
   511
		++ptr;
sl@0
   512
#else
sl@0
   513
// Basic deflation will store any match found, and not update the hash links for the
sl@0
   514
// data which is skipped
sl@0
   515
		if (match<=(KDeflateMinLength<<16))		// no match
sl@0
   516
			LitLenL(*ptr++);
sl@0
   517
		else
sl@0
   518
			{	// store the match
sl@0
   519
			TInt len=match>>16;
sl@0
   520
			SegmentL(len,match-(len<<16));
sl@0
   521
			ptr+=len;
sl@0
   522
			}
sl@0
   523
#endif
sl@0
   524
		} while (ptr+KDeflateMinLength-1<aEnd);
sl@0
   525
#ifdef __EXTRA_DEFLATE
sl@0
   526
	if (prev)
sl@0
   527
		{		// emit the stored match
sl@0
   528
		TInt len=prev>>16;
sl@0
   529
		SegmentL(len,prev-(len<<16));
sl@0
   530
		ptr+=len-1;
sl@0
   531
		}
sl@0
   532
#endif
sl@0
   533
	return ptr;
sl@0
   534
	}
sl@0
   535
sl@0
   536
//
sl@0
   537
// The generic deflation algorithm
sl@0
   538
//
sl@0
   539
void MDeflater::DeflateL(const TUint8* aBase,TInt aLength)
sl@0
   540
	{
sl@0
   541
	const TUint8* end=aBase+aLength;
sl@0
   542
	if (aLength>KDeflateMinLength)
sl@0
   543
		{	// deflation kicks in if there is enough data
sl@0
   544
		HDeflateHash& hash=HDeflateHash::NewLC(aLength);
sl@0
   545
		aBase=DoDeflateL(aBase,end,hash);
sl@0
   546
		CleanupStack::PopAndDestroy();
sl@0
   547
		}
sl@0
   548
	while (aBase<end)					// emit remaining bytes
sl@0
   549
		LitLenL(*aBase++);
sl@0
   550
	LitLenL(CDbStoreCompression::TEncoding::EEos);	// eos marker
sl@0
   551
	}
sl@0
   552
sl@0
   553
//
sl@0
   554
// Turn a (length,offset) pair into the deflation codes+extra bits before calling
sl@0
   555
// the specific LitLen(), Offset() and Extra() functions.
sl@0
   556
//
sl@0
   557
void MDeflater::SegmentL(TInt aLength,TInt aDistance)
sl@0
   558
	{
sl@0
   559
	__ASSERT(aLength>=KDeflateMinLength && aLength<=KDeflateMaxLength);
sl@0
   560
	aLength-=KDeflateMinLength;
sl@0
   561
	TInt extralen=0;
sl@0
   562
	TUint len=aLength;
sl@0
   563
	while (len>=8)
sl@0
   564
		{
sl@0
   565
		++extralen;
sl@0
   566
		len>>=1;
sl@0
   567
		}
sl@0
   568
	__ASSERT((extralen<<2)+len<CDbStoreCompression::TEncoding::ELengths);
sl@0
   569
	LitLenL((extralen<<2)+len+CDbStoreCompression::TEncoding::ELiterals);
sl@0
   570
	if (extralen)
sl@0
   571
		ExtraL(extralen,TUint(aLength)<<(32-extralen));
sl@0
   572
//
sl@0
   573
	__ASSERT(aDistance>0 && aDistance<=KDeflateMaxDistance);
sl@0
   574
	aDistance--;
sl@0
   575
	extralen=0;
sl@0
   576
	TUint dist=aDistance;
sl@0
   577
	while (dist>=8)
sl@0
   578
		{
sl@0
   579
		++extralen;
sl@0
   580
		dist>>=1;
sl@0
   581
		}
sl@0
   582
	__ASSERT((extralen<<2)+dist<CDbStoreCompression::TEncoding::EDistances);
sl@0
   583
	OffsetL((extralen<<2)+dist);
sl@0
   584
	if (extralen)
sl@0
   585
		ExtraL(extralen,TUint(aDistance)<<(32-extralen));
sl@0
   586
	}
sl@0
   587
sl@0
   588
// Class TDeflateStats
sl@0
   589
//
sl@0
   590
// This class analyses the data stream to generate the frequency tables 
sl@0
   591
// for the deflation algorithm
sl@0
   592
sl@0
   593
inline TDeflateStats::TDeflateStats(CDbStoreCompression::TEncoding& aEncoding)
sl@0
   594
	:iEncoding(aEncoding)
sl@0
   595
	{}
sl@0
   596
sl@0
   597
void TDeflateStats::LitLenL(TInt aCode)
sl@0
   598
	{
sl@0
   599
	++iEncoding.iLitLen[aCode];
sl@0
   600
	}
sl@0
   601
sl@0
   602
void TDeflateStats::OffsetL(TInt aCode)
sl@0
   603
	{
sl@0
   604
	++iEncoding.iDistance[aCode];
sl@0
   605
	}
sl@0
   606
sl@0
   607
void TDeflateStats::ExtraL(TInt,TUint)
sl@0
   608
	{}
sl@0
   609
sl@0
   610
// Class THuffEncoder
sl@0
   611
//
sl@0
   612
// This class generates the byte stream of huffman codes, writing them out to the stream
sl@0
   613
sl@0
   614
THuffEncoder::THuffEncoder(RWriteStream& aStream)
sl@0
   615
	:iStream(aStream),iCode(0),iBits(-8),iWrite(iBuf)
sl@0
   616
	{}
sl@0
   617
sl@0
   618
//
sl@0
   619
// Store a huffman code generated by Huffman::EncodingL()
sl@0
   620
//
sl@0
   621
void THuffEncoder::EncodeL(TUint32 aHuffCode)
sl@0
   622
	{
sl@0
   623
	EncodeL(aHuffCode<<(32-KHuffMaxCodeLength),aHuffCode>>KHuffMaxCodeLength);
sl@0
   624
	}
sl@0
   625
sl@0
   626
//
sl@0
   627
// Store aLength bits from the most significant bits of aCode
sl@0
   628
//
sl@0
   629
void THuffEncoder::EncodeL(TUint aCode,TInt aLength)
sl@0
   630
	{
sl@0
   631
	TInt bits=iBits;
sl@0
   632
	TUint code=iCode|(aCode>>(bits+8));
sl@0
   633
	bits+=aLength;
sl@0
   634
	if (bits>=0)
sl@0
   635
		{
sl@0
   636
		TUint8* write=iWrite;
sl@0
   637
		do
sl@0
   638
			{
sl@0
   639
			if (write-EBufSize==iBuf)
sl@0
   640
				{
sl@0
   641
				iStream.WriteL(iBuf,EBufSize);
sl@0
   642
				write=iBuf;
sl@0
   643
				}
sl@0
   644
			*write++=TUint8(code>>24);
sl@0
   645
			code<<=8;
sl@0
   646
			bits-=8;
sl@0
   647
			} while (bits>=0);
sl@0
   648
		iWrite=write;
sl@0
   649
		}
sl@0
   650
	iCode=code;
sl@0
   651
	iBits=bits;
sl@0
   652
	}
sl@0
   653
sl@0
   654
//
sl@0
   655
// Terminate the huffman coding. The longest code is always 1111111111
sl@0
   656
//
sl@0
   657
void THuffEncoder::CompleteL()
sl@0
   658
	{
sl@0
   659
	if (iBits>-8)
sl@0
   660
		EncodeL(0xffffffffu,-iBits);
sl@0
   661
	if (iWrite>iBuf)
sl@0
   662
		iStream.WriteL(iBuf,iWrite-iBuf);
sl@0
   663
	}
sl@0
   664
sl@0
   665
// Class TDeflater
sl@0
   666
//
sl@0
   667
// Extends MDeflater to provide huffman encoding of the output
sl@0
   668
sl@0
   669
//
sl@0
   670
// construct for encoding
sl@0
   671
//
sl@0
   672
inline TDeflater::TDeflater(THuffEncoder& aEncoder,const CDbStoreCompression::TEncoding& aEncoding)
sl@0
   673
	:iEncoder(aEncoder),iEncoding(aEncoding)
sl@0
   674
	{}
sl@0
   675
sl@0
   676
void TDeflater::LitLenL(TInt aCode)
sl@0
   677
	{
sl@0
   678
	iEncoder.EncodeL(iEncoding.iLitLen[aCode]);
sl@0
   679
	}
sl@0
   680
sl@0
   681
void TDeflater::OffsetL(TInt aCode)
sl@0
   682
	{
sl@0
   683
	iEncoder.EncodeL(iEncoding.iDistance[aCode]);
sl@0
   684
	}
sl@0
   685
sl@0
   686
void TDeflater::ExtraL(TInt aLen,TUint aBits)
sl@0
   687
	{
sl@0
   688
	iEncoder.EncodeL(aBits,aLen);
sl@0
   689
	}
sl@0
   690
sl@0
   691
// Class TInflater
sl@0
   692
//
sl@0
   693
// The inflation algorithm, complete with huffman decoding
sl@0
   694
sl@0
   695
TInflater::TInflater(const TUint8* aIn,const CDbStoreCompression::TEncoding& aEncoding)
sl@0
   696
	:iIn(aIn),iBits(KBitsInit),iLen(0),iLitLenTree(aEncoding.iLitLen),iDistTree(aEncoding.iDistance)
sl@0
   697
	{}
sl@0
   698
sl@0
   699
//
sl@0
   700
// consume all data lag in the history buffer, then decode to fill up the output buffer
sl@0
   701
//
sl@0
   702
TInt TInflater::Inflate()
sl@0
   703
	{
sl@0
   704
// empty the history buffer into the output
sl@0
   705
	const TUint8* data=iIn;
sl@0
   706
	TUint bits=iBits;
sl@0
   707
	const TUint8* from=iRptr;
sl@0
   708
	TInt len=iLen;
sl@0
   709
	TUint8* out=iOut;
sl@0
   710
	TUint8* const end=out+KDeflateMaxDistance;
sl@0
   711
	const TUint32* node;
sl@0
   712
	if (len)
sl@0
   713
		goto useHistory;
sl@0
   714
//
sl@0
   715
	if (bits&KBitsEOF)
sl@0
   716
		return 0;
sl@0
   717
//
sl@0
   718
	node=iLitLenTree;
sl@0
   719
	while (out<end)
sl@0
   720
		{
sl@0
   721
		// get a huffman code
sl@0
   722
		{
sl@0
   723
		TUint huff;
sl@0
   724
		for (;;)
sl@0
   725
			{
sl@0
   726
			huff=*node++;
sl@0
   727
			if ((bits<<=1)&KBitsEmpty)
sl@0
   728
				bits=*data++|KBitsFull;
sl@0
   729
			if (bits&KBitsNext)
sl@0
   730
				{
sl@0
   731
				if (huff&(KHuffTerminate<<16))
sl@0
   732
					break;
sl@0
   733
				}
sl@0
   734
			else
sl@0
   735
				{
sl@0
   736
				if (huff&KHuffTerminate)
sl@0
   737
					{
sl@0
   738
					huff<<=16;
sl@0
   739
					break;
sl@0
   740
					}
sl@0
   741
				else
sl@0
   742
					node=PtrAdd(node,huff);
sl@0
   743
				}
sl@0
   744
			}
sl@0
   745
		TInt val=TInt(huff>>17)-CDbStoreCompression::TEncoding::ELiterals;
sl@0
   746
		if (val<0)
sl@0
   747
			{
sl@0
   748
			*out++=TUint8(val);
sl@0
   749
			node=iLitLenTree;
sl@0
   750
			continue;			// another literal/length combo
sl@0
   751
			}
sl@0
   752
		if (val==CDbStoreCompression::TEncoding::EEos-CDbStoreCompression::TEncoding::ELiterals)
sl@0
   753
			{	// eos marker. we're done
sl@0
   754
			bits=KBitsEOF;
sl@0
   755
			break;
sl@0
   756
			}
sl@0
   757
		// get the extra bits for the code
sl@0
   758
		TInt code=val&0xff;
sl@0
   759
		if (code>=8)
sl@0
   760
			{	// xtra bits
sl@0
   761
			TInt xtra=(code>>2)-1;
sl@0
   762
			code-=xtra<<2;
sl@0
   763
			do
sl@0
   764
				{
sl@0
   765
				if ((bits<<=1)&KBitsEmpty)
sl@0
   766
					bits=*data++|KBitsFull;
sl@0
   767
				code<<=1;
sl@0
   768
				if (bits&KBitsNext)
sl@0
   769
					code|=1;
sl@0
   770
				} while (--xtra!=0);
sl@0
   771
			}
sl@0
   772
		if (val<KDeflateDistCodeBase-CDbStoreCompression::TEncoding::ELiterals)
sl@0
   773
			{	// length code... get the code
sl@0
   774
			len=code+KDeflateMinLength;
sl@0
   775
			__ASSERT(len<=KDeflateMaxLength);
sl@0
   776
			node=iDistTree;
sl@0
   777
			continue;			// read the huffman code
sl@0
   778
			}
sl@0
   779
		// distance code
sl@0
   780
		__ASSERT(code<KDeflateMaxDistance);
sl@0
   781
		from=out-(code+1);
sl@0
   782
		if (from+KDeflateMaxDistance<end)
sl@0
   783
			from+=KDeflateMaxDistance;
sl@0
   784
		}
sl@0
   785
useHistory:
sl@0
   786
		TInt tfr=Min(end-out,len);
sl@0
   787
		len-=tfr;
sl@0
   788
		do
sl@0
   789
			{
sl@0
   790
			*out++=*from++;
sl@0
   791
			if (from==end)
sl@0
   792
				from-=KDeflateMaxDistance;
sl@0
   793
			} while (--tfr!=0);
sl@0
   794
		node=iLitLenTree;
sl@0
   795
		};
sl@0
   796
	iIn=data;
sl@0
   797
	iBits=bits;
sl@0
   798
	iRptr=from;
sl@0
   799
	iLen=len;
sl@0
   800
	return out-iOut;
sl@0
   801
	}
sl@0
   802
sl@0
   803
inline const TUint8* TInflater::Ptr() const
sl@0
   804
	{return iOut;}
sl@0
   805
inline TInt TInflater::BufferSize()
sl@0
   806
	{return KDeflateMaxDistance;}
sl@0
   807
sl@0
   808
// Class HDeflateBuf
sl@0
   809
//
sl@0
   810
// This stream buffer applies the analysis or deflation and huffman coding
sl@0
   811
// on the entire stream data when it is committed
sl@0
   812
sl@0
   813
inline HDeflateBuf::HDeflateBuf(MStreamBuf* aHost,CDbStoreCompression::TEncoding& aEncoding,CBufBase* aBuf,TMode aMode)
sl@0
   814
	:iHost(aHost),iEncoding(aEncoding),iBuf(aBuf),iMode(aMode)
sl@0
   815
	{Set(*aBuf,0);}
sl@0
   816
sl@0
   817
HDeflateBuf* HDeflateBuf::NewL(MStreamBuf* aHost,CDbStoreCompression::TEncoding& aEncoding,TMode aMode)
sl@0
   818
	{
sl@0
   819
	CBufBase* buf=CBufFlat::NewL(512);
sl@0
   820
	CleanupStack::PushL(buf);
sl@0
   821
	HDeflateBuf* self=new(ELeave) HDeflateBuf(aHost,aEncoding,buf,aMode);
sl@0
   822
	CleanupStack::Pop();
sl@0
   823
	return self;
sl@0
   824
	}
sl@0
   825
sl@0
   826
inline HDeflateBuf::~HDeflateBuf()
sl@0
   827
	{delete iBuf;iHost.Release();}
sl@0
   828
sl@0
   829
void HDeflateBuf::DoRelease()
sl@0
   830
	{
sl@0
   831
	delete this;
sl@0
   832
	}
sl@0
   833
sl@0
   834
//
sl@0
   835
// This is where it all happens
sl@0
   836
//
sl@0
   837
void HDeflateBuf::DoSynchL()
sl@0
   838
	{
sl@0
   839
	if (iMode==EAnalysis)
sl@0
   840
		{
sl@0
   841
		TDeflateStats deflater(iEncoding);
sl@0
   842
		deflater.DeflateL(iBuf->Ptr(0).Ptr(),iBuf->Size());
sl@0
   843
		}
sl@0
   844
	else
sl@0
   845
		{
sl@0
   846
		THuffEncoder encoder(iHost);
sl@0
   847
		TDeflater deflater(encoder,iEncoding);
sl@0
   848
		deflater.DeflateL(iBuf->Ptr(0).Ptr(),iBuf->Size());
sl@0
   849
		encoder.CompleteL();
sl@0
   850
		iHost.CommitL();
sl@0
   851
		}
sl@0
   852
	}
sl@0
   853
sl@0
   854
// Class HInflateBuf
sl@0
   855
//
sl@0
   856
// Inflate the input stream. This is not a filter, it reads all the input, inflates it and
sl@0
   857
// keeps it in a memory buffer.
sl@0
   858
sl@0
   859
const TInt KInflateBufSize=0x800;	// 2K
sl@0
   860
sl@0
   861
HInflateBuf::HInflateBuf(CBufBase* aBuf)
sl@0
   862
	:iBuf(aBuf)
sl@0
   863
	{
sl@0
   864
	Set(*aBuf,0,ERead);
sl@0
   865
	}
sl@0
   866
sl@0
   867
inline HInflateBuf::~HInflateBuf()
sl@0
   868
	{delete iBuf;}
sl@0
   869
sl@0
   870
void HInflateBuf::DoRelease()
sl@0
   871
	{
sl@0
   872
	delete this;
sl@0
   873
	}
sl@0
   874
sl@0
   875
HInflateBuf* HInflateBuf::NewL(MStreamBuf* aHost,const CDbStoreCompression::TEncoding& aEncoding)
sl@0
   876
	{
sl@0
   877
	CBufFlat* host=CBufFlat::NewL(256);
sl@0
   878
	CleanupStack::PushL(host);
sl@0
   879
	TUint8 buffer[KInflateBufSize];
sl@0
   880
	for (;;)
sl@0
   881
		{
sl@0
   882
		TInt len=aHost->ReadL(buffer,KInflateBufSize);
sl@0
   883
		if (len)
sl@0
   884
			host->InsertL(host->Size(),buffer,len);
sl@0
   885
		if (len<KInflateBufSize)
sl@0
   886
			break;
sl@0
   887
		}
sl@0
   888
	CBufSeg* out=CBufSeg::NewL(256);
sl@0
   889
	CleanupStack::PushL(out);
sl@0
   890
	TInflater* inflater=new(ELeave) TInflater(host->Ptr(0).Ptr(),aEncoding);
sl@0
   891
	CleanupStack::PushL(inflater);
sl@0
   892
	for (;;)
sl@0
   893
		{
sl@0
   894
		TInt len=inflater->Inflate();
sl@0
   895
		if (len)
sl@0
   896
			out->InsertL(out->Size(),inflater->Ptr(),len);
sl@0
   897
		if (len<inflater->BufferSize())
sl@0
   898
			break;
sl@0
   899
		}
sl@0
   900
	HInflateBuf* buf=new(ELeave) HInflateBuf(out);
sl@0
   901
	CleanupStack::PopAndDestroy();	// inflater
sl@0
   902
	CleanupStack::Pop();			// out
sl@0
   903
	CleanupStack::PopAndDestroy();	// host
sl@0
   904
	aHost->Release();				// don't need this anymore
sl@0
   905
	return buf;
sl@0
   906
	}
sl@0
   907
sl@0
   908
// Class CDbStoreTable::Compressor
sl@0
   909
//
sl@0
   910
// This class processes an entire table for analysis or compression, using the
sl@0
   911
// CDbStoreRecords::AlterL() functionality and call back to ensure that all clusters
sl@0
   912
// and BLOBs are read and written.
sl@0
   913
sl@0
   914
inline CDbStoreTable::CCompressor::CCompressor()
sl@0
   915
	{}
sl@0
   916
sl@0
   917
CDbStoreTable::CCompressor::~CCompressor()
sl@0
   918
	{
sl@0
   919
	if (iTable)
sl@0
   920
		iTable->Close();
sl@0
   921
	iRow.Close();
sl@0
   922
	}
sl@0
   923
sl@0
   924
//
sl@0
   925
// Walk through every cluster in the table
sl@0
   926
//
sl@0
   927
void CDbStoreTable::CCompressor::ProcessL(CDbStoreTable* aTable)
sl@0
   928
	{
sl@0
   929
	iTable=aTable;
sl@0
   930
	CDbStoreRecords& rec=aTable->StoreRecordsL();
sl@0
   931
	for (TClusterId cluster=rec.Head();cluster!=KNullClusterId;cluster=rec.AlterL(cluster,*this))
sl@0
   932
		;
sl@0
   933
	}
sl@0
   934
sl@0
   935
//
sl@0
   936
// Compress every blob, and transfer the record from aRPtr to aWPtr
sl@0
   937
//
sl@0
   938
TUint8* CDbStoreTable::CCompressor::AlterRecordL(TUint8* aWPtr,const TUint8* aRPtr,TInt aLength)
sl@0
   939
	{
sl@0
   940
	if (iTable->Def().Columns().HasLongColumns())
sl@0
   941
		{
sl@0
   942
		iTable->CopyToRowL(iRow,TPtrC8(aRPtr,aLength));
sl@0
   943
		CDbBlobSpace* blobs=iTable->BlobsL();
sl@0
   944
		TDbColNo col=1;
sl@0
   945
		HDbColumnSet::TIteratorC iter=iTable->Def().Columns().Begin();
sl@0
   946
		const HDbColumnSet::TIteratorC end=iTable->Def().Columns().End();
sl@0
   947
		do
sl@0
   948
			{
sl@0
   949
			if (!TDbCol::IsLong(iter->Type()))
sl@0
   950
				continue;
sl@0
   951
			TDbBlob& blob=CONST_CAST(TDbBlob&,TDbColumnC(iRow,col).Blob());
sl@0
   952
			if (blob.IsInline())
sl@0
   953
				continue;
sl@0
   954
			// do what has to be done...?
sl@0
   955
			TUint8* data=(TUint8*)User::AllocLC(blob.Size());
sl@0
   956
			blobs->ReadLC(blob.Id(),iter->Type())->ReadL(data,blob.Size());
sl@0
   957
			CleanupStack::PopAndDestroy();	// stream buffer
sl@0
   958
			// re-write the Blob to compress it
sl@0
   959
			blobs->DeleteL(blob.Id());
sl@0
   960
			blob.SetId(blobs->CreateL(iter->Type(),data,blob.Size()));
sl@0
   961
			CleanupStack::PopAndDestroy();	// data
sl@0
   962
			} while (++col,++iter<end);
sl@0
   963
		iTable->CopyFromRow(aWPtr,iRow);
sl@0
   964
		}
sl@0
   965
	else
sl@0
   966
		Mem::Copy(aWPtr,aRPtr,aLength);
sl@0
   967
	return aWPtr+aLength;
sl@0
   968
	}
sl@0
   969
sl@0
   970
// Class CDbStoreCompression
sl@0
   971
//
sl@0
   972
// This class manages the compression for the database, applying filters as appropriate
sl@0
   973
// It also defines the extrenalisation format for the huffman trees
sl@0
   974
sl@0
   975
const TInt KDeflationCodes=3*(CDbStoreCompression::TEncoding::ELitLens+CDbStoreCompression::TEncoding::EDistances);
sl@0
   976
sl@0
   977
inline CDbStoreCompression::CDbStoreCompression()
sl@0
   978
//	:iState(EAnalysis)
sl@0
   979
	{}
sl@0
   980
sl@0
   981
CDbStoreCompression* CDbStoreCompression::NewL()
sl@0
   982
	{
sl@0
   983
	return new(ELeave) CDbStoreCompression;
sl@0
   984
	}
sl@0
   985
sl@0
   986
//
sl@0
   987
// Build huffman codings from the freqeuncy tables
sl@0
   988
//
sl@0
   989
void CDbStoreCompression::EncodeL()
sl@0
   990
	{
sl@0
   991
	__ASSERT(iState==EAnalysis);
sl@0
   992
	TUint32* p=iEncoding[0].iLitLen;
sl@0
   993
	TUint32* end=p+KDeflationCodes;
sl@0
   994
	do
sl@0
   995
		{
sl@0
   996
		Huffman::EncodingL(p,TEncoding::ELitLens);
sl@0
   997
		p+=TEncoding::ELitLens;
sl@0
   998
		Huffman::EncodingL(p,TEncoding::EDistances);
sl@0
   999
		p+=TEncoding::EDistances;
sl@0
  1000
		} while (p<end);
sl@0
  1001
	iState=EEncoding;
sl@0
  1002
	}
sl@0
  1003
sl@0
  1004
//
sl@0
  1005
// Store the encoding tables as a sequence of code lengths
sl@0
  1006
// The code lengths (0-25) are themselves huffman coded, and the meta coding is stored first
sl@0
  1007
//
sl@0
  1008
void CDbStoreCompression::ExternalizeL(RWriteStream& aStream) const
sl@0
  1009
	{
sl@0
  1010
	__ASSERT(iState==EEncoding);
sl@0
  1011
	const TUint32* base=iEncoding[0].iLitLen;
sl@0
  1012
	const TUint32* end=base+KDeflationCodes;
sl@0
  1013
	TUint32 codes[KDeflateMetaCodes];
sl@0
  1014
	Mem::FillZ(codes,sizeof(codes));
sl@0
  1015
	const TUint32* p=base;
sl@0
  1016
	do ++codes[*p++>>KHuffMaxCodeLength]; while (p<end);
sl@0
  1017
	Huffman::EncodingL(codes,KDeflateMetaCodes);
sl@0
  1018
// save the meta encoding
sl@0
  1019
	p=codes+KDeflateMetaCodes;
sl@0
  1020
	do
sl@0
  1021
		{
sl@0
  1022
		TUint c0=*--p;
sl@0
  1023
		TUint c1=*--p;
sl@0
  1024
		c0>>=KHuffMaxCodeLength;
sl@0
  1025
		c1>>=KHuffMaxCodeLength;
sl@0
  1026
		aStream.WriteUint8L((c0<<4)|c1);
sl@0
  1027
		} while (p>codes);
sl@0
  1028
// write the encoding
sl@0
  1029
	THuffEncoder encoder(aStream);
sl@0
  1030
	p=base;
sl@0
  1031
	do encoder.EncodeL(codes[*p++>>KHuffMaxCodeLength]); while (p<end);
sl@0
  1032
	encoder.CompleteL();
sl@0
  1033
	}
sl@0
  1034
sl@0
  1035
//
sl@0
  1036
// Internalize a previous saved encoding
sl@0
  1037
//
sl@0
  1038
void CDbStoreCompression::InternalizeL(RReadStream& aStream)
sl@0
  1039
	{
sl@0
  1040
	__ASSERT(iState!=EEncoding);
sl@0
  1041
//
sl@0
  1042
// read the meta encoding
sl@0
  1043
	TUint32 decode[KDeflateMetaCodes];
sl@0
  1044
	TUint32* p=decode+KDeflateMetaCodes;
sl@0
  1045
	do
sl@0
  1046
		{
sl@0
  1047
		TUint8 c=aStream.ReadUint8L();
sl@0
  1048
		*--p=c>>4;
sl@0
  1049
		*--p=c&0xf;
sl@0
  1050
		} while (p>decode);
sl@0
  1051
	Huffman::Decoding(decode,KDeflateMetaCodes);
sl@0
  1052
// decode the encoding
sl@0
  1053
	p=iEncoding[0].iLitLen;
sl@0
  1054
	TUint32* end=p+KDeflationCodes;
sl@0
  1055
	TUint bits=KBitsInit;
sl@0
  1056
	do
sl@0
  1057
		{
sl@0
  1058
		const TUint32* node=decode;
sl@0
  1059
		TUint huff;
sl@0
  1060
		for (;;)
sl@0
  1061
			{
sl@0
  1062
			huff=*node++;
sl@0
  1063
			if ((bits<<=1)&KBitsEmpty)
sl@0
  1064
				bits=aStream.ReadUint8L()|KBitsFull;
sl@0
  1065
			if (bits&KBitsNext)
sl@0
  1066
				{
sl@0
  1067
				if (huff&(KHuffTerminate<<16))
sl@0
  1068
					break;
sl@0
  1069
				}
sl@0
  1070
			else
sl@0
  1071
				{
sl@0
  1072
				if (huff&KHuffTerminate)
sl@0
  1073
					{
sl@0
  1074
					huff<<=16;
sl@0
  1075
					break;
sl@0
  1076
					}
sl@0
  1077
				else
sl@0
  1078
					node=PtrAdd(node,huff);
sl@0
  1079
				}
sl@0
  1080
			}
sl@0
  1081
		*p++=huff>>17;
sl@0
  1082
		} while (p<end);
sl@0
  1083
// convert the length tables into huffman decoding trees
sl@0
  1084
	p=iEncoding[0].iLitLen;
sl@0
  1085
	do
sl@0
  1086
		{
sl@0
  1087
		Huffman::Decoding(p,TEncoding::ELitLens);
sl@0
  1088
		p+=TEncoding::ELitLens;
sl@0
  1089
		Huffman::Decoding(p,TEncoding::EDistances,KDeflateDistCodeBase);
sl@0
  1090
		p+=TEncoding::EDistances;
sl@0
  1091
		} while (p<end);
sl@0
  1092
	if (iState==EAnalysis)
sl@0
  1093
		iState=EDecoding;
sl@0
  1094
	}
sl@0
  1095
sl@0
  1096
//
sl@0
  1097
// Apply an inflation filter to a read stream
sl@0
  1098
//
sl@0
  1099
MStreamBuf* CDbStoreCompression::FilterL(MStreamBuf* aHost,TUint32,RDbStoreReadStream::TType aType)
sl@0
  1100
	{
sl@0
  1101
	if (iState==EDecoding || iState==EInflating)
sl@0
  1102
		return HInflateBuf::NewL(aHost,iEncoding[aType]);
sl@0
  1103
	return aHost;
sl@0
  1104
	}
sl@0
  1105
sl@0
  1106
//
sl@0
  1107
// Apply a statistics or inflation filter to a write stream
sl@0
  1108
//
sl@0
  1109
MStreamBuf* CDbStoreCompression::FilterL(MStreamBuf* aHost,TUint32,RDbStoreWriteStream::TType aType)
sl@0
  1110
	{
sl@0
  1111
	TState s=iState;
sl@0
  1112
	if (s==EDecoding)
sl@0
  1113
		__LEAVE(KErrWrite);		// read-only database
sl@0
  1114
	else if (s!=EInflating)
sl@0
  1115
		{
sl@0
  1116
		__ASSERT(TInt(EAnalysis)==TInt(HDeflateBuf::EAnalysis));
sl@0
  1117
		__ASSERT(TInt(EEncoding)==TInt(HDeflateBuf::EDeflate));
sl@0
  1118
		return HDeflateBuf::NewL(aHost,iEncoding[aType],HDeflateBuf::TMode(s));
sl@0
  1119
		}
sl@0
  1120
	return aHost;
sl@0
  1121
	}
sl@0
  1122
sl@0
  1123
// Class CDbStoreDatabase
sl@0
  1124
//
sl@0
  1125
// Compression related code is maintained in this source file
sl@0
  1126
sl@0
  1127
//
sl@0
  1128
// Iterate across all tables applying analysis or compression to them
sl@0
  1129
//
sl@0
  1130
void CDbStoreDatabase::CompressTablesL()
sl@0
  1131
	{
sl@0
  1132
	TSglQueIterC<CDbStoreDef> iter(SchemaL());
sl@0
  1133
	const CDbStoreDef* def;
sl@0
  1134
	while ((def=iter++)!=0)
sl@0
  1135
		{
sl@0
  1136
		CDbStoreTable::CCompressor* comp=new(ELeave) CDbStoreTable::CCompressor;
sl@0
  1137
		CleanupStack::PushL(comp);
sl@0
  1138
		comp->ProcessL(STATIC_CAST(CDbStoreTable*,TableL(*def)));
sl@0
  1139
		CleanupStack::PopAndDestroy();	// comp
sl@0
  1140
		}
sl@0
  1141
	}
sl@0
  1142
sl@0
  1143
//
sl@0
  1144
// Compress or decompress the whole database
sl@0
  1145
//
sl@0
  1146
void CDbStoreDatabase::CompressL(TStreamId aStreamId,TZipType aZip)
sl@0
  1147
	{
sl@0
  1148
	__ASSERT(iStore);
sl@0
  1149
	iSchemaId=aStreamId;
sl@0
  1150
// read the databse header for encryption information
sl@0
  1151
	RStoreReadStream strm;
sl@0
  1152
	strm.OpenLC(Store(),aStreamId);
sl@0
  1153
	ReadHeaderL(strm);
sl@0
  1154
	CleanupStack::PopAndDestroy();	// strm
sl@0
  1155
	InitPagePoolL();
sl@0
  1156
//
sl@0
  1157
	if (iVersion==EDbStoreCompressed)
sl@0
  1158
		{
sl@0
  1159
		iCompression->Inflate();
sl@0
  1160
		if (aZip==EDeflate)
sl@0
  1161
			__LEAVE(KErrArgument);		// already compressed
sl@0
  1162
		}
sl@0
  1163
	else if (aZip==EInflate)
sl@0
  1164
		__LEAVE(KErrArgument);		// not compressed
sl@0
  1165
	else
sl@0
  1166
		{	// deflate pass #1: analyse the database
sl@0
  1167
		CompressionL();				// construct the compression filter
sl@0
  1168
		Transaction().DDLBeginLC();
sl@0
  1169
		CompressTablesL();
sl@0
  1170
		iClusterCache->FlushL();		// force through the stats buffer
sl@0
  1171
		ReplaceSchemaL();				// force through the stats buffer
sl@0
  1172
		CleanupStack::PopAndDestroy();	// rollback after analysis!
sl@0
  1173
		iCompression->EncodeL();
sl@0
  1174
		}
sl@0
  1175
// now inflate or deflate the data
sl@0
  1176
	Transaction().DDLBeginLC();
sl@0
  1177
	CompressTablesL();
sl@0
  1178
	iVersion=TUint8(aZip==EDeflate ? EDbStoreCompressed : EDbStoreVersion2);
sl@0
  1179
	Transaction().DDLCommitL();
sl@0
  1180
	CleanupStack::Pop();		// rollback not required
sl@0
  1181
	}
sl@0
  1182
sl@0
  1183
void CDbStoreDatabase::CompressL(CStreamStore* aStore,TStreamId aStreamId,TZipType aZip)
sl@0
  1184
	{
sl@0
  1185
	CDbStoreDatabase* self=NewLC(aStore);
sl@0
  1186
	CDbObject* db=self->InterfaceL();	// a reference to the database is required
sl@0
  1187
	CleanupStack::Pop();	// self
sl@0
  1188
	db->PushL();
sl@0
  1189
	self->Transaction().DDLPrepareL(*db);
sl@0
  1190
	self->CompressL(aStreamId,aZip);
sl@0
  1191
	CleanupStack::PopAndDestroy();	// db
sl@0
  1192
	}
sl@0
  1193
sl@0
  1194
// Class RDbStoreDatabase
sl@0
  1195
sl@0
  1196
EXPORT_C void RDbStoreDatabase::CompressL(CStreamStore& aStore,TStreamId aId)
sl@0
  1197
	{
sl@0
  1198
	CDbStoreDatabase::CompressL(&aStore,aId,CDbStoreDatabase::EDeflate);
sl@0
  1199
	}
sl@0
  1200
sl@0
  1201
EXPORT_C void RDbStoreDatabase::DecompressL(CStreamStore& aStore,TStreamId aId)
sl@0
  1202
	{
sl@0
  1203
	CDbStoreDatabase::CompressL(&aStore,aId,CDbStoreDatabase::EInflate);
sl@0
  1204
	}