os/kernelhwsrv/kernel/eka/euser/us_decode.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_decode.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
#include <cpudefs.h>
sl@0
    23
sl@0
    24
const TInt KHuffTerminate=0x0001;
sl@0
    25
const TUint32 KBranch1=sizeof(TUint32)<<16;
sl@0
    26
_LIT(KCat,"Huffman");
sl@0
    27
sl@0
    28
TUint32* HuffmanSubTree(TUint32* aPtr,const TUint32* aValue,TUint32** aLevel)
sl@0
    29
//
sl@0
    30
// write the subtree below aPtr and return the head
sl@0
    31
//
sl@0
    32
	{
sl@0
    33
	TUint32* l=*aLevel++;
sl@0
    34
	if (l>aValue)
sl@0
    35
		{
sl@0
    36
		TUint32* sub0=HuffmanSubTree(aPtr,aValue,aLevel);	// 0-tree first
sl@0
    37
		aPtr=HuffmanSubTree(sub0,aValue-(aPtr-sub0)-1,aLevel);			// 1-tree
sl@0
    38
		TInt branch0=(TUint8*)sub0-(TUint8*)(aPtr-1);
sl@0
    39
		*--aPtr=KBranch1|branch0;
sl@0
    40
		}
sl@0
    41
	else if (l==aValue)
sl@0
    42
		{
sl@0
    43
		TUint term0=*aValue--;						// 0-term
sl@0
    44
		aPtr=HuffmanSubTree(aPtr,aValue,aLevel);			// 1-tree
sl@0
    45
		*--aPtr=KBranch1|(term0>>16);
sl@0
    46
		}
sl@0
    47
	else	// l<iNext
sl@0
    48
		{
sl@0
    49
		TUint term0=*aValue--;						// 0-term
sl@0
    50
		TUint term1=*aValue--;
sl@0
    51
		*--aPtr=(term1>>16<<16)|(term0>>16);
sl@0
    52
		}
sl@0
    53
	return aPtr;
sl@0
    54
	}
sl@0
    55
sl@0
    56
/** Create a canonical Huffman decoding tree
sl@0
    57
sl@0
    58
	This generates the huffman decoding tree used by TBitInput::HuffmanL() to read huffman
sl@0
    59
	encoded data. The input is table of code lengths, as generated by Huffman::HuffmanL()
sl@0
    60
	and must represent a valid huffman code.
sl@0
    61
	
sl@0
    62
	@param aHuffman The table of code lengths as generated by Huffman::HuffmanL()
sl@0
    63
	@param aNumCodes The number of codes in the table
sl@0
    64
	@param aDecodeTree The space for the decoding tree. This must be the same
sl@0
    65
		size as the code-length table, and can safely be the same memory
sl@0
    66
	@param  aSymbolBase the base value for the output 'symbols' from the decoding tree, by default
sl@0
    67
		this is zero.
sl@0
    68
sl@0
    69
	@panic "USER ???" If the provided code is not a valid Huffman coding
sl@0
    70
sl@0
    71
	@see IsValid()
sl@0
    72
	@see HuffmanL()
sl@0
    73
*/
sl@0
    74
EXPORT_C void Huffman::Decoding(const TUint32 aHuffman[],TInt aNumCodes,TUint32 aDecodeTree[],TInt aSymbolBase)
sl@0
    75
	{
sl@0
    76
	__ASSERT_ALWAYS(IsValid(aHuffman,aNumCodes),User::Panic(KCat,EHuffmanInvalidCoding));
sl@0
    77
//
sl@0
    78
	TFixedArray<TInt,KMaxCodeLength> counts;
sl@0
    79
	counts.Reset();
sl@0
    80
	TInt codes=0;
sl@0
    81
	TInt ii;
sl@0
    82
	for (ii=0;ii<aNumCodes;++ii)
sl@0
    83
		{
sl@0
    84
		TInt len=aHuffman[ii];
sl@0
    85
		aDecodeTree[ii]=len;
sl@0
    86
		if (--len>=0)
sl@0
    87
			{
sl@0
    88
			++counts[len];
sl@0
    89
			++codes;
sl@0
    90
			}
sl@0
    91
		}
sl@0
    92
//
sl@0
    93
	TFixedArray<TUint32*,KMaxCodeLength> level;
sl@0
    94
	TUint32* lit=aDecodeTree+codes;
sl@0
    95
	for (ii=0;ii<KMaxCodeLength;++ii)
sl@0
    96
		{
sl@0
    97
		level[ii]=lit;
sl@0
    98
		lit-=counts[ii];
sl@0
    99
		}
sl@0
   100
	aSymbolBase=(aSymbolBase<<17)+(KHuffTerminate<<16);
sl@0
   101
	for (ii=0;ii<aNumCodes;++ii)
sl@0
   102
		{
sl@0
   103
		TUint len=TUint8(aDecodeTree[ii]);
sl@0
   104
		if (len)
sl@0
   105
			*--level[len-1]|=(ii<<17)+aSymbolBase;
sl@0
   106
		}
sl@0
   107
	if (codes==1)	// codes==1 special case: incomplete tree
sl@0
   108
		{
sl@0
   109
		TUint term=aDecodeTree[0]>>16;
sl@0
   110
		aDecodeTree[0]=term|(term<<16); // 0- and 1-terminate at root
sl@0
   111
		}
sl@0
   112
	else if (codes>1)
sl@0
   113
		HuffmanSubTree(aDecodeTree+codes-1,aDecodeTree+codes-1,&level[0]);
sl@0
   114
	}
sl@0
   115
sl@0
   116
// The decoding tree for the externalised code
sl@0
   117
const TUint32 HuffmanDecoding[]=
sl@0
   118
	{
sl@0
   119
	0x0004006c,
sl@0
   120
	0x00040064,
sl@0
   121
	0x0004005c,
sl@0
   122
	0x00040050,
sl@0
   123
	0x00040044,
sl@0
   124
	0x0004003c,
sl@0
   125
	0x00040034,
sl@0
   126
	0x00040021,
sl@0
   127
	0x00040023,
sl@0
   128
	0x00040025,
sl@0
   129
	0x00040027,
sl@0
   130
	0x00040029,
sl@0
   131
	0x00040014,
sl@0
   132
	0x0004000c,
sl@0
   133
	0x00040035,
sl@0
   134
	0x00390037,
sl@0
   135
	0x00330031,
sl@0
   136
	0x0004002b,
sl@0
   137
	0x002f002d,
sl@0
   138
	0x001f001d,
sl@0
   139
	0x001b0019,
sl@0
   140
	0x00040013,
sl@0
   141
	0x00170015,
sl@0
   142
	0x0004000d,
sl@0
   143
	0x0011000f,
sl@0
   144
	0x000b0009,
sl@0
   145
	0x00070003,
sl@0
   146
	0x00050001
sl@0
   147
	};
sl@0
   148
sl@0
   149
/** Restore a canonical huffman encoding from a bit stream
sl@0
   150
sl@0
   151
	The encoding must have been stored using Huffman::ExternalizeL(). The resulting
sl@0
   152
	code-length table can be used to create an encoding table using Huffman::Encoding()
sl@0
   153
	or a decoding tree using Huffman::Decoding().
sl@0
   154
	
sl@0
   155
	@param aInput The input stream with the encoding
sl@0
   156
	@param aHuffman The internalized code-length table is placed here
sl@0
   157
	@param aNumCodes The number of huffman codes in the table
sl@0
   158
sl@0
   159
	@leave TBitInput::HuffmanL()
sl@0
   160
sl@0
   161
	@see ExternalizeL()
sl@0
   162
*/
sl@0
   163
EXPORT_C void Huffman::InternalizeL(TBitInput& aInput,TUint32 aHuffman[],TInt aNumCodes)
sl@0
   164
// See ExternalizeL for a description of the format
sl@0
   165
	{
sl@0
   166
	// initialise move-to-front list
sl@0
   167
	TFixedArray<TUint8,Huffman::KMetaCodes> list;
sl@0
   168
	for (TInt i=0;i<list.Count();++i)
sl@0
   169
		list[i]=TUint8(i);
sl@0
   170
	TInt last=0;
sl@0
   171
	// extract codes, reverse rle-0 and mtf encoding in one pass
sl@0
   172
	TUint32* p=aHuffman;
sl@0
   173
	const TUint32* end=aHuffman+aNumCodes;
sl@0
   174
	TUint rl=0;
sl@0
   175
	while (p+rl<end)
sl@0
   176
		{
sl@0
   177
		TInt c=aInput.HuffmanL(HuffmanDecoding);
sl@0
   178
		// c is now 0..28
sl@0
   179
		if (c<2)
sl@0
   180
			{
sl@0
   181
			// one of the zero codes used by RLE-0
sl@0
   182
			// update he run-length
sl@0
   183
			rl+=rl+c+1;
sl@0
   184
			}
sl@0
   185
		else
sl@0
   186
			{
sl@0
   187
			if(rl >= TUint(end-p))
sl@0
   188
				User::Leave(KErrCorrupt);
sl@0
   189
			while (rl>0)
sl@0
   190
				{
sl@0
   191
				*p++=last;
sl@0
   192
				--rl;
sl@0
   193
				}
sl@0
   194
			--c; // c is now 1..27
sl@0
   195
			list[0]=TUint8(last);
sl@0
   196
			last=list[c];
sl@0
   197
			Mem::Copy(&list[1],&list[0],c);
sl@0
   198
			*p++=last;
sl@0
   199
			}
sl@0
   200
		}
sl@0
   201
sl@0
   202
	while (p<end)
sl@0
   203
		*p++=last;
sl@0
   204
sl@0
   205
	}
sl@0
   206
sl@0
   207
// bit-stream input class
sl@0
   208
sl@0
   209
inline TUint reverse(TUint aVal)
sl@0
   210
//
sl@0
   211
// Reverse the byte-order of a 32 bit value
sl@0
   212
// This generates optimal ARM code (4 instructions)
sl@0
   213
//
sl@0
   214
	{
sl@0
   215
	TUint v=(aVal<<16)|(aVal>>16);
sl@0
   216
	v^=aVal;
sl@0
   217
	v&=0xff00ffff;
sl@0
   218
	aVal=(aVal>>8)|(aVal<<24);
sl@0
   219
	return aVal^(v>>8);
sl@0
   220
	}
sl@0
   221
sl@0
   222
/** Construct a bit stream input object
sl@0
   223
sl@0
   224
	Following construction the bit stream is ready for reading bits, but will
sl@0
   225
	immediately call UnderflowL() as the input buffer is empty.
sl@0
   226
*/
sl@0
   227
EXPORT_C TBitInput::TBitInput()
sl@0
   228
	:iCount(0),iRemain(0)
sl@0
   229
	{}
sl@0
   230
sl@0
   231
/** Construct a bit stream input object over a buffer
sl@0
   232
sl@0
   233
	Following construction the bit stream is ready for reading bits from
sl@0
   234
	the specified buffer.
sl@0
   235
sl@0
   236
	@param aPtr The address of the buffer containing the bit stream
sl@0
   237
	@param aLength The length of the bitstream in bits
sl@0
   238
	@param aOffset The bit offset from the start of the buffer to the bit stream (defaults to zero)
sl@0
   239
*/
sl@0
   240
EXPORT_C TBitInput::TBitInput(const TUint8* aPtr, TInt aLength, TInt aOffset)
sl@0
   241
	{
sl@0
   242
	Set(aPtr,aLength,aOffset);
sl@0
   243
	}
sl@0
   244
sl@0
   245
/** Set the memory buffer to use for input
sl@0
   246
sl@0
   247
	Bits will be read from this buffer until it is empty, at which point
sl@0
   248
	UnderflowL() will be called.
sl@0
   249
	
sl@0
   250
	@param aPtr The address of the buffer containing the bit stream
sl@0
   251
	@param aLength The length of the bitstream in bits
sl@0
   252
	@param aOffset The bit offset from the start of the buffer to the bit stream (defaults to zero)
sl@0
   253
*/
sl@0
   254
EXPORT_C void TBitInput::Set(const TUint8* aPtr, TInt aLength, TInt aOffset)
sl@0
   255
	{
sl@0
   256
	TUint p=(TUint)aPtr;
sl@0
   257
	p+=aOffset>>3;			// nearest byte to the specified bit offset
sl@0
   258
	aOffset&=7;				// bit offset within the byte
sl@0
   259
	const TUint32* ptr=(const TUint32*)(p&~3);	// word containing this byte
sl@0
   260
	aOffset+=(p&3)<<3;		// bit offset within the word
sl@0
   261
	if (aLength==0)
sl@0
   262
		iCount=0;
sl@0
   263
	else
sl@0
   264
		{
sl@0
   265
		// read the first few bits of the stream
sl@0
   266
		iBits=reverse(*ptr++)<<aOffset;
sl@0
   267
		aOffset=32-aOffset;
sl@0
   268
		aLength-=aOffset;
sl@0
   269
		if (aLength<0)
sl@0
   270
			aOffset+=aLength;
sl@0
   271
		iCount=aOffset;
sl@0
   272
		}
sl@0
   273
	iRemain=aLength;
sl@0
   274
	iPtr=ptr;
sl@0
   275
	}
sl@0
   276
sl@0
   277
#ifndef __HUFFMAN_MACHINE_CODED__
sl@0
   278
sl@0
   279
/** Read a single bit from the input
sl@0
   280
sl@0
   281
	Return the next bit in the input stream. This will call UnderflowL() if
sl@0
   282
	there are no more bits available.
sl@0
   283
sl@0
   284
	@return The next bit in the stream
sl@0
   285
sl@0
   286
	@leave "UnderflowL()" It the bit stream is exhausted more UnderflowL is called
sl@0
   287
		to get more data
sl@0
   288
*/
sl@0
   289
EXPORT_C TUint TBitInput::ReadL()
sl@0
   290
	{
sl@0
   291
	TInt c=iCount;
sl@0
   292
	TUint bits=iBits;
sl@0
   293
	if (--c<0)
sl@0
   294
		return ReadL(1);
sl@0
   295
	iCount=c;
sl@0
   296
	iBits=bits<<1;
sl@0
   297
	return bits>>31;
sl@0
   298
	}
sl@0
   299
sl@0
   300
/** Read a multi-bit value from the input
sl@0
   301
sl@0
   302
	Return the next few bits as an unsigned integer. The last bit read is
sl@0
   303
	the least significant bit of the returned value, and the value is
sl@0
   304
	zero extended to return a 32-bit result.
sl@0
   305
sl@0
   306
	A read of zero bits will always reaturn zero.
sl@0
   307
	
sl@0
   308
	This will call UnderflowL() if there are not enough bits available.
sl@0
   309
sl@0
   310
	@param aSize The number of bits to read
sl@0
   311
sl@0
   312
	@return The bits read from the stream
sl@0
   313
sl@0
   314
	@leave "UnderflowL()" It the bit stream is exhausted more UnderflowL is called
sl@0
   315
		to get more data
sl@0
   316
*/
sl@0
   317
EXPORT_C TUint TBitInput::ReadL(TInt aSize)
sl@0
   318
	{
sl@0
   319
	if (!aSize)
sl@0
   320
		return 0;
sl@0
   321
	TUint val=0;
sl@0
   322
	TUint bits=iBits;
sl@0
   323
	iCount-=aSize;
sl@0
   324
	while (iCount<0)
sl@0
   325
		{
sl@0
   326
		// need more bits
sl@0
   327
#ifdef __CPU_X86
sl@0
   328
		// X86 does not allow shift-by-32
sl@0
   329
		if (iCount+aSize!=0)
sl@0
   330
			val|=bits>>(32-(iCount+aSize))<<(-iCount);	// scrub low order bits
sl@0
   331
#else
sl@0
   332
		val|=bits>>(32-(iCount+aSize))<<(-iCount);	// scrub low order bits
sl@0
   333
#endif
sl@0
   334
		aSize=-iCount;	// bits still required
sl@0
   335
		if (iRemain>0)
sl@0
   336
			{
sl@0
   337
			bits=reverse(*iPtr++);
sl@0
   338
			iCount+=32;
sl@0
   339
			iRemain-=32;
sl@0
   340
			if (iRemain<0)
sl@0
   341
				iCount+=iRemain;
sl@0
   342
			}
sl@0
   343
		else
sl@0
   344
			{
sl@0
   345
			UnderflowL();
sl@0
   346
			bits=iBits;
sl@0
   347
			iCount-=aSize;
sl@0
   348
			}
sl@0
   349
		}
sl@0
   350
#ifdef __CPU_X86
sl@0
   351
	// X86 does not allow shift-by-32
sl@0
   352
	iBits=aSize==32?0:bits<<aSize;
sl@0
   353
#else
sl@0
   354
	iBits=bits<<aSize;
sl@0
   355
#endif
sl@0
   356
	return val|(bits>>(32-aSize));
sl@0
   357
	}
sl@0
   358
sl@0
   359
/** Read and decode a Huffman Code
sl@0
   360
sl@0
   361
	Interpret the next bits in the input as a Huffman code in the specified
sl@0
   362
	decoding. The decoding tree should be the output from Huffman::Decoding().
sl@0
   363
sl@0
   364
	@param aTree The huffman decoding tree
sl@0
   365
sl@0
   366
	@return The symbol that was decoded
sl@0
   367
	
sl@0
   368
	@leave "UnderflowL()" It the bit stream is exhausted more UnderflowL is called
sl@0
   369
		to get more data
sl@0
   370
*/
sl@0
   371
EXPORT_C TUint TBitInput::HuffmanL(const TUint32* aTree)
sl@0
   372
	{
sl@0
   373
	TUint huff=0;
sl@0
   374
	do
sl@0
   375
		{
sl@0
   376
		aTree=PtrAdd(aTree,huff>>16);
sl@0
   377
		huff=*aTree;
sl@0
   378
		if (ReadL()==0)
sl@0
   379
			huff<<=16;
sl@0
   380
		} while ((huff&0x10000u)==0);
sl@0
   381
	return huff>>17;
sl@0
   382
	}
sl@0
   383
sl@0
   384
#endif
sl@0
   385
sl@0
   386
/** Handle an empty input buffer
sl@0
   387
sl@0
   388
	This virtual function is called when the input buffer is empty and
sl@0
   389
	more bits are required. It should reset the input buffer with more
sl@0
   390
	data using Set().
sl@0
   391
sl@0
   392
	A derived class can replace this to read the data from a file
sl@0
   393
	(for example) before reseting the input buffer.
sl@0
   394
sl@0
   395
	@leave KErrUnderflow The default implementation leaves
sl@0
   396
*/
sl@0
   397
void TBitInput::UnderflowL()
sl@0
   398
	{
sl@0
   399
	User::Leave(KErrUnderflow);
sl@0
   400
	}