os/kernelhwsrv/kernel/eka/euser/us_encode.cpp
author sl@SLION-WIN7.fritz.box
Fri, 15 Jun 2012 03:10:57 +0200
changeset 0 bde4ae8d615e
permissions -rw-r--r--
First public contribution.
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 the License "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
// e32\euser\us_encode.cpp
sl@0
    15
// 
sl@0
    16
//
sl@0
    17
sl@0
    18
#include "e32huffman.h"
sl@0
    19
#include <e32base.h>
sl@0
    20
#include <e32base_private.h>
sl@0
    21
#include <e32panic.h>
sl@0
    22
sl@0
    23
_LIT(KCat,"Huffman");
sl@0
    24
// local definitions used for Huffman code generation
sl@0
    25
typedef TUint16 THuff;		/** @internal */
sl@0
    26
const THuff KLeaf=0x8000;	/** @internal */
sl@0
    27
struct TNode
sl@0
    28
/** @internal */
sl@0
    29
	{
sl@0
    30
	TUint iCount;
sl@0
    31
	THuff iLeft;
sl@0
    32
	THuff iRight;
sl@0
    33
	};
sl@0
    34
sl@0
    35
/** recursive function to calculate the code lengths from the node tree
sl@0
    36
sl@0
    37
	@internalComponent
sl@0
    38
*/
sl@0
    39
void HuffmanLengthsL(TUint32* aLengths,const TNode* aNodes,TInt aNode,TInt aLen)
sl@0
    40
	{
sl@0
    41
	if (++aLen>Huffman::KMaxCodeLength)
sl@0
    42
		User::Leave(KErrOverflow);
sl@0
    43
sl@0
    44
	const TNode& node=aNodes[aNode];
sl@0
    45
	TUint x=node.iLeft;
sl@0
    46
	if (x&KLeaf)
sl@0
    47
		aLengths[x&~KLeaf]=aLen;
sl@0
    48
	else
sl@0
    49
		HuffmanLengthsL(aLengths,aNodes,x,aLen);
sl@0
    50
	x=node.iRight;
sl@0
    51
	if (x&KLeaf)
sl@0
    52
		aLengths[x&~KLeaf]=aLen;
sl@0
    53
	else
sl@0
    54
		HuffmanLengthsL(aLengths,aNodes,x,aLen);
sl@0
    55
	}
sl@0
    56
sl@0
    57
/**	Insert the {aCount,aValue} pair into the already sorted array of nodes
sl@0
    58
sl@0
    59
	@internalComponent
sl@0
    60
*/
sl@0
    61
void InsertInOrder(TNode* aNodes, TInt aSize, TUint aCount, TInt aVal)
sl@0
    62
	{
sl@0
    63
	// Uses Insertion sort following a binary search...
sl@0
    64
	TInt l=0, r=aSize;
sl@0
    65
	while (l < r)
sl@0
    66
		{
sl@0
    67
		TInt m = (l+r) >> 1;
sl@0
    68
		if (aNodes[m].iCount<aCount)
sl@0
    69
			r=m;
sl@0
    70
		else
sl@0
    71
			l=m+1;
sl@0
    72
		}
sl@0
    73
	Mem::Copy(aNodes+l+1,aNodes+l,sizeof(TNode)*(aSize-l));
sl@0
    74
	aNodes[l].iCount=aCount;
sl@0
    75
	aNodes[l].iRight=TUint16(aVal);
sl@0
    76
	}
sl@0
    77
sl@0
    78
/** Generate a Huffman code
sl@0
    79
sl@0
    80
	This generates a Huffman code for a given set of code frequencies. The output
sl@0
    81
	is a table of code lengths which can be used to build canonincal encoding tables
sl@0
    82
	or decoding trees for use with the TBitInput and TBitOutput classes.
sl@0
    83
sl@0
    84
	Entries in the table with a frequency of zero will have a zero code length
sl@0
    85
	and thus no associated huffman encoding. If each such symbol should have a
sl@0
    86
	maximum length encoding, they must be given at least a frequency of 1.
sl@0
    87
sl@0
    88
	For an alphabet of n symbols, this algorithm has a transient memory overhead
sl@0
    89
	of 8n, and a time complexity of O(n*log(n)).
sl@0
    90
sl@0
    91
	@param aFrequency The table of code frequencies
sl@0
    92
	@param aNumCodes The number of codes in the table
sl@0
    93
	@param aHuffman The table for the output code-length table. This must be
sl@0
    94
		the same size as the frequency table, and can safely be the same table
sl@0
    95
sl@0
    96
	@leave KErrNoMemory If memory used for code generation cannot be allocated
sl@0
    97
sl@0
    98
  	@panic "USER ???" If the number of codes exceeds Huffman::KMaxCodes
sl@0
    99
*/
sl@0
   100
EXPORT_C void Huffman::HuffmanL(const TUint32 aFrequency[],TInt aNumCodes,TUint32 aHuffman[])
sl@0
   101
	{
sl@0
   102
	__ASSERT_ALWAYS(TUint(aNumCodes)<=TUint(KMaxCodes),User::Panic(KCat,EHuffmanTooManyCodes));
sl@0
   103
sl@0
   104
	// Sort the values into decreasing order of frequency
sl@0
   105
	//
sl@0
   106
	TNode* nodes = new(ELeave) TNode[aNumCodes];
sl@0
   107
	CleanupArrayDeletePushL(nodes);
sl@0
   108
	TInt lCount=0;
sl@0
   109
sl@0
   110
	for (TInt ii=0;ii<aNumCodes;++ii)
sl@0
   111
		{
sl@0
   112
		TInt c=aFrequency[ii];
sl@0
   113
		if (c!=0)
sl@0
   114
			InsertInOrder(nodes,lCount++,c,ii|KLeaf);
sl@0
   115
		}
sl@0
   116
sl@0
   117
	// default code length is zero
sl@0
   118
	Mem::FillZ(aHuffman,aNumCodes*sizeof(TUint32));
sl@0
   119
sl@0
   120
	if (lCount==0)
sl@0
   121
		{
sl@0
   122
		// no codes with frequency>0. No code has a length
sl@0
   123
		}
sl@0
   124
	else if (lCount==1)
sl@0
   125
		{
sl@0
   126
		// special case for a single value (always encode as "0")
sl@0
   127
		aHuffman[nodes[0].iRight&~KLeaf]=1;
sl@0
   128
		}
sl@0
   129
	else
sl@0
   130
		{
sl@0
   131
		// Huffman algorithm: pair off least frequent nodes and reorder
sl@0
   132
		//
sl@0
   133
		do
sl@0
   134
			{
sl@0
   135
			--lCount;
sl@0
   136
			TUint c=nodes[lCount].iCount + nodes[lCount-1].iCount;
sl@0
   137
			nodes[lCount].iLeft=nodes[lCount-1].iRight;
sl@0
   138
			// re-order the leaves now to reflect new combined frequency 'c'
sl@0
   139
			InsertInOrder(nodes,lCount-1,c,lCount);
sl@0
   140
			} while (lCount>1);
sl@0
   141
		// generate code lengths in aHuffman[]
sl@0
   142
		HuffmanLengthsL(aHuffman,nodes,1,0);
sl@0
   143
		}
sl@0
   144
	CleanupStack::PopAndDestroy(nodes);
sl@0
   145
sl@0
   146
	__ASSERT_DEBUG(IsValid(aHuffman,aNumCodes),User::Panic(KCat,EHuffmanInvalidCoding));
sl@0
   147
	}
sl@0
   148
sl@0
   149
/** Validate a Huffman encoding
sl@0
   150
sl@0
   151
	This verifies that a Huffman coding described by the code lengths is valid.
sl@0
   152
	In particular, it ensures that no code exceeds the maximum length and
sl@0
   153
	that it is possible to generate a canonical coding for the specified lengths.
sl@0
   154
	
sl@0
   155
	@param aHuffman The table of code lengths as generated by Huffman::HuffmanL()
sl@0
   156
	@param aNumCodes The number of codes in the table
sl@0
   157
sl@0
   158
	@return True if the code is valid, otherwise false
sl@0
   159
*/
sl@0
   160
EXPORT_C TBool Huffman::IsValid(const TUint32 aHuffman[],TInt aNumCodes)
sl@0
   161
	{
sl@0
   162
	// The code is valid if one of the following holds:
sl@0
   163
	// (a) the code exactly fills the 'code space'
sl@0
   164
	// (b) there is only a single symbol with code length 1
sl@0
   165
	// (c) there are no encoded symbols
sl@0
   166
	//
sl@0
   167
	TUint remain=1<<KMaxCodeLength;
sl@0
   168
	TInt totlen=0;
sl@0
   169
	for (const TUint32* p=aHuffman+aNumCodes; p>aHuffman;)
sl@0
   170
		{
sl@0
   171
		TInt len=*--p;
sl@0
   172
		if (len>0)
sl@0
   173
			{
sl@0
   174
			totlen+=len;
sl@0
   175
			if (len>KMaxCodeLength)
sl@0
   176
				return EFalse;
sl@0
   177
			TUint c=1<<(KMaxCodeLength-len);
sl@0
   178
			if (c>remain)
sl@0
   179
				return EFalse;
sl@0
   180
			remain-=c;
sl@0
   181
			}
sl@0
   182
		}
sl@0
   183
sl@0
   184
	return remain==0 || totlen<=1;
sl@0
   185
	}
sl@0
   186
sl@0
   187
/** Create a canonical Huffman encoding table
sl@0
   188
sl@0
   189
	This generates the huffman codes used by TBitOutput::HuffmanL() to write huffman
sl@0
   190
	encoded data. The input is table of code lengths, as generated by Huffman::HuffmanL()
sl@0
   191
	and must represent a valid huffman code.
sl@0
   192
	
sl@0
   193
	@param aHuffman The table of code lengths as generated by Huffman::HuffmanL()
sl@0
   194
	@param aNumCodes The number of codes in the table
sl@0
   195
	@param aEncodeTable The table for the output huffman codes. This must be
sl@0
   196
		the same size as the code-length table, and can safely be the same table
sl@0
   197
sl@0
   198
	@panic "USER ???" If the provided code is not a valid Huffman coding
sl@0
   199
	
sl@0
   200
	@see IsValid()
sl@0
   201
	@see HuffmanL()
sl@0
   202
*/
sl@0
   203
EXPORT_C void Huffman::Encoding(const TUint32 aHuffman[],TInt aNumCodes,TUint32 aEncodeTable[])
sl@0
   204
	{
sl@0
   205
	__ASSERT_ALWAYS(IsValid(aHuffman,aNumCodes),User::Panic(KCat,EHuffmanInvalidCoding));
sl@0
   206
sl@0
   207
	TFixedArray<TInt,KMaxCodeLength> lenCount;
sl@0
   208
	lenCount.Reset();
sl@0
   209
sl@0
   210
	TInt ii;
sl@0
   211
	for (ii=0;ii<aNumCodes;++ii)
sl@0
   212
		{
sl@0
   213
		TInt len=aHuffman[ii]-1;
sl@0
   214
		if (len>=0)
sl@0
   215
			++lenCount[len];
sl@0
   216
		}
sl@0
   217
sl@0
   218
	TFixedArray<TUint,KMaxCodeLength> nextCode;
sl@0
   219
	TUint code=0;
sl@0
   220
	for (ii=0;ii<KMaxCodeLength;++ii)
sl@0
   221
		{
sl@0
   222
		code<<=1;
sl@0
   223
		nextCode[ii]=code;
sl@0
   224
		code+=lenCount[ii];
sl@0
   225
		}
sl@0
   226
sl@0
   227
	for (ii=0;ii<aNumCodes;++ii)
sl@0
   228
		{
sl@0
   229
		TInt len=aHuffman[ii];
sl@0
   230
		if (len==0)
sl@0
   231
			aEncodeTable[ii]=0;
sl@0
   232
		else
sl@0
   233
			{
sl@0
   234
			aEncodeTable[ii] = (nextCode[len-1]<<(KMaxCodeLength-len))|(len<<KMaxCodeLength);
sl@0
   235
			++nextCode[len-1];
sl@0
   236
			}
sl@0
   237
		}
sl@0
   238
	}
sl@0
   239
sl@0
   240
/** the encoding table for the externalised code
sl@0
   241
	@internalComponent
sl@0
   242
*/
sl@0
   243
const TUint32 HuffmanEncoding[]=
sl@0
   244
	{
sl@0
   245
	0x10000000,
sl@0
   246
	0x1c000000,
sl@0
   247
	0x12000000,
sl@0
   248
	0x1d000000,
sl@0
   249
	0x26000000,
sl@0
   250
	0x26800000,
sl@0
   251
	0x2f000000,
sl@0
   252
	0x37400000,
sl@0
   253
	0x37600000,
sl@0
   254
	0x37800000,
sl@0
   255
	0x3fa00000,
sl@0
   256
	0x3fb00000,
sl@0
   257
	0x3fc00000,
sl@0
   258
	0x3fd00000,
sl@0
   259
	0x47e00000,
sl@0
   260
	0x47e80000,
sl@0
   261
	0x47f00000,
sl@0
   262
	0x4ff80000,
sl@0
   263
	0x57fc0000,
sl@0
   264
	0x5ffe0000,
sl@0
   265
	0x67ff0000,
sl@0
   266
	0x77ff8000,
sl@0
   267
	0x7fffa000,
sl@0
   268
	0x7fffb000,
sl@0
   269
	0x7fffc000,
sl@0
   270
	0x7fffd000,
sl@0
   271
	0x7fffe000,
sl@0
   272
	0x87fff000,
sl@0
   273
	0x87fff800
sl@0
   274
	};
sl@0
   275
sl@0
   276
/** encode 0a as '0' and 0b as '1', return number of symbols created
sl@0
   277
sl@0
   278
	@internalComponent
sl@0
   279
*/
sl@0
   280
void EncodeRunLengthL(TBitOutput& aOutput, TInt aLength)
sl@0
   281
	{
sl@0
   282
	if (aLength>0)
sl@0
   283
		{
sl@0
   284
		EncodeRunLengthL(aOutput,(aLength-1)>>1);
sl@0
   285
		aOutput.HuffmanL(HuffmanEncoding[1-(aLength&1)]);
sl@0
   286
		}
sl@0
   287
	}
sl@0
   288
sl@0
   289
/** Store a canonical huffman encoding in compact form
sl@0
   290
sl@0
   291
	As the encoding is canonical, only the code lengths of each code needs to be saved.
sl@0
   292
sl@0
   293
	Due to the nature of code length tables, these can usually be stored very compactly
sl@0
   294
	by encoding the encoding itself, hence the use of the bit output stream.
sl@0
   295
	
sl@0
   296
	@param aOutput The output stream for the encoding
sl@0
   297
	@param aHuffman The table of code lengths as generated by Huffman::HuffmanL()
sl@0
   298
	@param aNumCodes The number of huffman codes in the table
sl@0
   299
sl@0
   300
	@leave TBitOutput::HuffmanL()
sl@0
   301
*/
sl@0
   302
EXPORT_C void Huffman::ExternalizeL(TBitOutput& aOutput,const TUint32 aHuffman[],TInt aNumCodes)
sl@0
   303
	{
sl@0
   304
	// We assume that the code length table is generated by the huffman generator,
sl@0
   305
	// in which case the maxmimum code length is 27 bits.
sl@0
   306
	//
sl@0
   307
	// We apply three transformations to the data:
sl@0
   308
	// 1. the data goes through a move-to-front coder
sl@0
   309
	// 2. apply a rle-0 coder which replace runs of '0' with streams of '0a' and '0b'
sl@0
   310
	// 3. encode the result using a predefined (average) huffman coding
sl@0
   311
	//
sl@0
   312
	// This can be done in a single pass over the data, avoiding the need for additional
sl@0
   313
	// memory.
sl@0
   314
	//
sl@0
   315
	// initialise the list for the MTF coder
sl@0
   316
	TFixedArray<TUint8,Huffman::KMetaCodes> list;
sl@0
   317
	TInt i;
sl@0
   318
	for (i=0;i<list.Count();++i)
sl@0
   319
		list[i]=TUint8(i);
sl@0
   320
	TInt last=0;
sl@0
   321
sl@0
   322
	TInt rl=0;
sl@0
   323
	const TUint32* p32=aHuffman;
sl@0
   324
	const TUint32* e32=p32+aNumCodes;
sl@0
   325
	while (p32<e32)
sl@0
   326
		{
sl@0
   327
		TInt c=*p32++;
sl@0
   328
		if (c==last)
sl@0
   329
			++rl;	// repeat of last symbol
sl@0
   330
		else
sl@0
   331
			{
sl@0
   332
			// encode run-length
sl@0
   333
			EncodeRunLengthL(aOutput,rl);
sl@0
   334
			rl=0;
sl@0
   335
			// find code in MTF list
sl@0
   336
			TInt j;
sl@0
   337
			for (j=1;list[j]!=c;++j)
sl@0
   338
				;
sl@0
   339
			// store this code
sl@0
   340
			aOutput.HuffmanL(HuffmanEncoding[j+1]);
sl@0
   341
			// adjust list for MTF algorithm
sl@0
   342
			while (--j>0)
sl@0
   343
				list[j+1]=list[j];
sl@0
   344
			list[1]=TUint8(last);
sl@0
   345
			last=c;
sl@0
   346
			}
sl@0
   347
		}
sl@0
   348
	// encod any remaining run-length
sl@0
   349
	EncodeRunLengthL(aOutput,rl);
sl@0
   350
	}
sl@0
   351
sl@0
   352
sl@0
   353
/** Construct a bit stream output object
sl@0
   354
sl@0
   355
	Following construction the bit stream is ready for writing bits, but will first call
sl@0
   356
	OverflowL() as the output buffer is 'full'. A derived class can detect this state as
sl@0
   357
	Ptr() will return null.
sl@0
   358
*/
sl@0
   359
EXPORT_C TBitOutput::TBitOutput()
sl@0
   360
	:iCode(0),iBits(-8),iPtr(0),iEnd(0)
sl@0
   361
	{}
sl@0
   362
sl@0
   363
/** Construct a bit stream output object over a buffer
sl@0
   364
sl@0
   365
	Data will be written to the buffer until it is full, at which point OverflowL() will
sl@0
   366
	be called. This should handle the data and then can Set() again to reset the buffer
sl@0
   367
	for further output.
sl@0
   368
	
sl@0
   369
	@param aBuf The buffer for output
sl@0
   370
	@param aSize The size of the buffer in bytes
sl@0
   371
*/
sl@0
   372
EXPORT_C TBitOutput::TBitOutput(TUint8* aBuf,TInt aSize)
sl@0
   373
	:iCode(0),iBits(-8),iPtr(aBuf),iEnd(aBuf+aSize)
sl@0
   374
	{}
sl@0
   375
sl@0
   376
/** Write a huffman code
sl@0
   377
sl@0
   378
	This expects a huffman code value as generated by Huffman::Encoding()
sl@0
   379
sl@0
   380
	@param aHuffCode The huffman code write to the stream
sl@0
   381
sl@0
   382
	@leave OverflowL() If the output buffer is full, OverflowL() is called
sl@0
   383
*/
sl@0
   384
EXPORT_C void TBitOutput::HuffmanL(TUint aHuffCode)
sl@0
   385
	{
sl@0
   386
	DoWriteL(aHuffCode<<(32-Huffman::KMaxCodeLength),aHuffCode>>Huffman::KMaxCodeLength);
sl@0
   387
	}
sl@0
   388
sl@0
   389
/** Write an arbitrary integer value
sl@0
   390
sl@0
   391
	Write an unsigned integer using the number of bits specified. Only
sl@0
   392
	the low order bits of the value are written to the output, most
sl@0
   393
	significant bit first.
sl@0
   394
sl@0
   395
	@param aValue The value to write to the stream
sl@0
   396
	@param aLength The number of bits to output
sl@0
   397
sl@0
   398
	@leave OverflowL() If the output buffer is full, OverflowL() is called
sl@0
   399
*/
sl@0
   400
EXPORT_C void TBitOutput::WriteL(TUint aValue,TInt aLength)
sl@0
   401
	{
sl@0
   402
	if (aLength)
sl@0
   403
		DoWriteL(aValue<<=32-aLength,aLength);
sl@0
   404
	}
sl@0
   405
sl@0
   406
/** Pad the bitstream to the next byte boundary
sl@0
   407
sl@0
   408
	Terminate the bitstream by padding the last byte with the requested value.
sl@0
   409
	Following this operation the bitstream can continue to be used, the data will
sl@0
   410
	start at the next byte.
sl@0
   411
sl@0
   412
	@param aPadding The bit value to pad the final byte with
sl@0
   413
sl@0
   414
	@leave OverflowL() If the output buffer is full, OverflowL() is called
sl@0
   415
*/
sl@0
   416
EXPORT_C void TBitOutput::PadL(TUint aPadding)
sl@0
   417
	{
sl@0
   418
	if (iBits>-8)
sl@0
   419
		WriteL(aPadding?0xffffffffu:0,-iBits);
sl@0
   420
	}
sl@0
   421
sl@0
   422
/** Write the higher order bits to the stream
sl@0
   423
	
sl@0
   424
	@internalComponent
sl@0
   425
*/
sl@0
   426
void TBitOutput::DoWriteL(TUint aBits,TInt aSize)
sl@0
   427
	{
sl@0
   428
	if (aSize>25)
sl@0
   429
		{
sl@0
   430
		// cannot process >25 bits in a single pass
sl@0
   431
		// so do the top 8 bits first
sl@0
   432
		ASSERT(aSize<=32);
sl@0
   433
		DoWriteL(aBits&0xff000000u,8);
sl@0
   434
		aBits<<=8;
sl@0
   435
		aSize-=8;
sl@0
   436
		}
sl@0
   437
sl@0
   438
	TInt bits=iBits;
sl@0
   439
	TUint code=iCode|(aBits>>(bits+8));
sl@0
   440
	bits+=aSize;
sl@0
   441
	if (bits>=0)
sl@0
   442
		{
sl@0
   443
		TUint8* p=iPtr;
sl@0
   444
		do
sl@0
   445
			{
sl@0
   446
			if (p==iEnd)
sl@0
   447
				{
sl@0
   448
				// run out of buffer space so invoke the overflow handler
sl@0
   449
				iPtr=p;
sl@0
   450
				OverflowL();
sl@0
   451
				p=iPtr;
sl@0
   452
				ASSERT(p!=iEnd);
sl@0
   453
				}
sl@0
   454
			*p++=TUint8(code>>24);
sl@0
   455
			code<<=8;
sl@0
   456
			bits-=8;
sl@0
   457
			} while (bits>=0);
sl@0
   458
		iPtr=p;
sl@0
   459
		}
sl@0
   460
	iCode=code;
sl@0
   461
	iBits=bits;
sl@0
   462
	}
sl@0
   463
sl@0
   464
/** Handle a full output buffer
sl@0
   465
sl@0
   466
	This virtual function is called when the output buffer is full. It should deal
sl@0
   467
	with the data in the buffer before reseting the buffer using Set(), allowing
sl@0
   468
	further data to be written.
sl@0
   469
sl@0
   470
	A derived class can replace this to write the data to a file (for example)
sl@0
   471
	before marking the buffer as empty.
sl@0
   472
sl@0
   473
	@leave KErrOverflow The default implementation leaves
sl@0
   474
*/
sl@0
   475
void TBitOutput::OverflowL()
sl@0
   476
	{
sl@0
   477
	User::Leave(KErrOverflow);
sl@0
   478
	}