kernel/eka/include/byte_pair_compress.h
changeset 0 a41df078684a
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kernel/eka/include/byte_pair_compress.h	Mon Oct 19 15:55:17 2009 +0100
@@ -0,0 +1,317 @@
+// Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of the License "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+// e32\include\byte_pair_compress.h
+// This header file contains both the prototype and implementation for the byte pair compressor.
+// This is done to facilitate sharing the code between the e32 test code and the tools.  The
+// implementation is only included if the macro BYTE_PAIR_COMPRESS_INCLUDE_IMPLEMENTATION is
+// defined.
+// 
+// WARNING: This file contains some APIs which are internal and are subject
+//          to change without notice. Such APIs should therefore not be used
+//          outside the Kernel and Hardware Services package.
+//
+
+#ifndef __BYTE_PAIR_COMPRESS_H__
+#define __BYTE_PAIR_COMPRESS_H__
+
+#include <e32std.h>
+
+/**
+ * @internalTechnology
+ *
+ * Compress up to 4096 bytes of data usign the byte-pair compression algorithm.
+ *
+ * @param aDest Destination buffer, must be at least four times the size of the source data.
+ * @param aSrc  Source data to compress.
+ * @param aSize The size of the source data.
+ */
+extern TInt BytePairCompress(TUint8* aDest, TUint8* aSrc, TInt aSize);
+
+#ifdef BYTE_PAIR_COMPRESS_INCLUDE_IMPLEMENTATION
+
+const TInt BlockSize = 0x1000;
+TInt ExtraSave = 0;
+
+TUint16 PairCount[0x10000];
+TUint16 PairBuffer[BlockSize*2];
+
+TUint16 GlobalPairs[0x10000] = {0};
+TUint16 GlobalTokenCounts[0x100] = {0};
+
+TUint16 ByteCount[0x100+4];
+
+void CountBytes(TUint8* data, TInt size)
+	{
+	memset(ByteCount,0,sizeof(ByteCount));
+	TUint8* dataEnd = data+size;
+	while(data<dataEnd)
+		++ByteCount[*data++];
+	}
+
+inline void ByteUsed(TInt b)
+	{
+	ByteCount[b] = 0xffff;
+	}
+
+int TieBreak(int b1,int b2)
+	{
+	return -ByteCount[b1]-ByteCount[b2];
+	}
+
+TInt MostCommonPair(TInt& pair, TUint8* data, TInt size, TInt minFrequency, TInt marker)
+	{
+	memset(PairCount,0,sizeof(PairCount));
+	TUint8* dataEnd = data+size-1;
+	TInt pairsFound = 0;
+	TInt lastPair = -1;
+	while(data<dataEnd)
+		{
+		TInt b1 = *data++;
+		if(b1==marker)
+			{
+			// skip marker and following byte
+			lastPair = -1;
+			++data;
+			continue;
+			}
+		TInt b2 = *data;
+		if(b2==marker)
+			{
+			// skip marker and following byte
+			lastPair = -1;
+			data+=2;
+			continue;
+			}
+		TInt p = (b2<<8)|b1;
+		if(p==lastPair)
+			{
+			// ensure a pair of identical bytes don't get double counted
+			lastPair = -1;
+			continue;
+			}
+		lastPair = p;
+		++PairCount[p];
+		if(PairCount[p]==minFrequency)
+			PairBuffer[pairsFound++] = (TUint16)p;
+		}
+
+	TInt bestCount = -1;
+	TInt bestPair = -1;
+	TInt bestTieBreak = 0;
+	TInt p;
+	while(pairsFound--)
+		{
+		p = PairBuffer[pairsFound];
+		TInt f=PairCount[p];
+		if(f>bestCount)
+			{
+			bestCount = f;
+			bestPair = p;
+			bestTieBreak = TieBreak(p&0xff,p>>8);
+			}
+		else if(f==bestCount)
+			{
+			TInt tieBreak = TieBreak(p&0xff,p>>8);
+			if(tieBreak>bestTieBreak)
+				{
+				bestCount = f;
+				bestPair = p;
+				bestTieBreak = tieBreak;
+				}
+			}
+		}
+	pair = bestPair;
+	return bestCount;
+	}
+
+TInt LeastCommonByte(TInt& byte)
+	{
+	TInt bestCount = 0xffff;
+	TInt bestByte = -1;
+	for(TInt b = 0; b<0x100; b++)
+		{
+		TInt f = ByteCount[b];
+		if(f<bestCount)
+			{
+			bestCount = f;
+			bestByte = b;
+			}
+		}
+	byte = bestByte;
+	return bestCount;
+	}
+
+TInt BytePairCompress(TUint8* dst, TUint8* src, TInt size)
+	{
+	TInt originalSize = size;
+	TUint8* dst2 = dst+size*2;
+	TUint8* in = src;
+	TUint8* out = dst;
+
+	TUint8 tokens[0x100*3];
+	TInt tokenCount = 0;
+
+	CountBytes(in,size);
+
+	TInt marker = -1;
+	TInt overhead = 1+3+LeastCommonByte(marker);
+	ByteUsed(marker);
+
+	TUint8* inEnd = in+size;
+	TUint8* outStart = out;
+	while(in<inEnd)
+		{
+		TInt b=*in++;
+		if(b==marker)
+			*out++ = (TUint8)b;
+		*out++ = (TUint8)b;
+		}
+	size = out-outStart;
+
+	TInt outToggle = 1;
+	in = dst;
+	out = dst2;
+
+	for(TInt r=256; r>0; --r)
+		{
+		TInt byte;
+		TInt byteCount = LeastCommonByte(byte);
+		TInt pair;
+		TInt pairCount = MostCommonPair(pair,in,size,overhead+1,marker);
+		TInt saving = pairCount-byteCount;
+		if(saving<=overhead)
+			break;
+
+		overhead = 3;
+		if(tokenCount>=32)
+			overhead = 2;
+
+		TUint8* d=tokens+3*tokenCount;
+		++tokenCount;
+		*d++ = (TUint8)byte;
+		ByteUsed(byte);
+		*d++ = (TUint8)pair;
+		ByteUsed(pair&0xff);
+		*d++ = (TUint8)(pair>>8);
+		ByteUsed(pair>>8);
+		++GlobalPairs[pair];
+
+		inEnd = in+size;
+		outStart = out;
+		while(in<inEnd)
+			{
+			TInt b=*in++;
+			if(b==marker)
+				{
+				*out++ = (TUint8)marker;
+				b = *in++;
+				}
+			else if(b==byte)
+				{
+				*out++ = (TUint8)marker;
+				--byteCount;
+				}
+			else if(b==(pair&0xff) && in<inEnd && *in==(pair>>8))
+				{
+				++in;
+				b = byte;
+				--pairCount;
+				}
+			*out++ = (TUint8)b;
+			}
+		ASSERT(!byteCount);
+		ASSERT(!pairCount);
+		size = out-outStart;
+
+		outToggle ^= 1;
+		if(outToggle)
+			{
+			in = dst;
+			out = dst2;
+			}
+		else
+			{
+			in = dst2;
+			out = dst;
+			}
+		}
+
+	// sort tokens with a bubble sort...
+	for(TInt x=0; x<tokenCount-1; x++)
+		for(TInt y=x+1; y<tokenCount; y++)
+			if(tokens[x*3]>tokens[y*3])
+				{
+				TInt z = tokens[x*3];
+				tokens[x*3] = tokens[y*3];
+				tokens[y*3] = (TUint8)z;
+				z = tokens[x*3+1];
+				tokens[x*3+1] = tokens[y*3+1];
+				tokens[y*3+1] = (TUint8)z;
+				z = tokens[x*3+2];
+				tokens[x*3+2] = tokens[y*3+2];
+				tokens[y*3+2] = (TUint8)z;
+				}
+
+	// check for not being able to compress...
+	if(size>originalSize)
+		{
+		*dst++ = 0; // store zero token count
+		memcpy(dst,src,originalSize); // store original data
+		return originalSize+1;
+		}
+
+	// make sure data is in second buffer (dst2)
+	if(in!=dst2)
+		memcpy(dst2,dst,size);
+
+	// store tokens...
+	TUint8* originalDst = dst;
+	*dst++ = (TUint8)tokenCount;
+	if(tokenCount)
+		{
+		*dst++ = (TUint8)marker;
+		if(tokenCount<32)
+			{
+			memcpy(dst,tokens,tokenCount*3);
+			dst += tokenCount*3;
+			}
+		else
+			{
+			TUint8* bitMask = dst;
+			memset(bitMask,0,32);
+			dst += 32;
+			TUint8* d=tokens;
+			do
+				{
+				TInt t=*d++;
+				bitMask[t>>3] |= (1<<(t&7));
+				*dst++ = *d++;
+				*dst++ = *d++;
+				}
+			while(--tokenCount);
+			}
+		}
+	// store data...
+	memcpy(dst,dst2,size);
+	dst += size;
+
+	// get stats...
+	++GlobalTokenCounts[tokenCount];
+
+	// return total size of compressed data...
+	return dst-originalDst;
+	}
+
+#endif
+#endif