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