--- a/e32tools/e32lib/e32image/deflate/encode.cpp Thu Nov 04 09:07:09 2010 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,491 +0,0 @@
-// Copyright (c) 1998-2009 Nokia Corporation and/or its subsidiary(-ies).
-// All rights reserved.
-// This component and the accompanying materials are made available
-// under the terms of "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:
-// e32tools\petran\Szip\encode.cpp
-//
-//
-
-#include "huffman.h"
-#include "panic.h"
-#include <e32base.h>
-#include "h_utl.h"
-#include <assert.h>
-#include "farray.h"
-#include <stdlib.h>
-
-void User::Invariant()
- {
- fprintf(stderr, "User::Invariant() called\n");
- exit(1);
- }
-
-// local definitions used for Huffman code generation
-typedef TUint16 THuff; /** @internal */
-const THuff KLeaf=0x8000; /** @internal */
-struct TNode
-/** @internal */
- {
- TUint iCount;
- THuff iLeft;
- THuff iRight;
- };
-
-void HuffmanLengthsL(TUint32* aLengths,const TNode* aNodes,TInt aNode,TInt aLen)
-/** recursive function to calculate the code lengths from the node tree
-
- @internal
-*/
- {
- if (++aLen>Huffman::KMaxCodeLength)
- Panic(EHuffmanBufferOverflow);
-
- const TNode& node=aNodes[aNode];
- TUint x=node.iLeft;
- if (x&KLeaf)
- aLengths[x&~KLeaf]=aLen;
- else
- HuffmanLengthsL(aLengths,aNodes,x,aLen);
- x=node.iRight;
- if (x&KLeaf)
- aLengths[x&~KLeaf]=aLen;
- else
- HuffmanLengthsL(aLengths,aNodes,x,aLen);
- }
-
-void InsertInOrder(TNode* aNodes, TInt aSize, TUint aCount, TInt aVal)
-/** Insert the {aCount,aValue} pair into the already sorted array of nodes
-
- @internal
-*/
- {
- // Uses Insertion sort following a binary search...
- TInt l=0, r=aSize;
- while (l < r)
- {
- TInt m = (l+r) >> 1;
- if (aNodes[m].iCount<aCount)
- r=m;
- else
- l=m+1;
- }
- HMem::Copy(aNodes+l+1,aNodes+l,sizeof(TNode)*(aSize-l));
- aNodes[l].iCount=aCount;
- aNodes[l].iRight=TUint16(aVal);
- }
-
-void Huffman::HuffmanL(const TUint32 aFrequency[],TInt aNumCodes,TUint32 aHuffman[])
-/** Generate a Huffman code
-
- This generates a Huffman code for a given set of code frequencies. The output
- is a table of code lengths which can be used to build canonincal encoding tables
- or decoding trees for use with the TBitInput and TBitOutput classes.
-
- Entries in the table with a frequency of zero will have a zero code length
- and thus no associated huffman encoding. If each such symbol should have a
- maximum length encoding, they must be given at least a frequency of 1.
-
- For an alphabet of n symbols, this algorithm has a transient memory overhead
- of 8n, and a time complexity of O(n*log(n)).
-
- @param "const TUint32 aFrequency[]" The table of code frequencies
- @param "TInt aNumCodes" The number of codes in the table
- @param "TUint32 aHuffman[]" The table for the output code-length table. This must be
- the same size as the frequency table, and can safely be the same table
-
- @leave "KErrNoMemory" If memory used for code generation cannot be allocated
-
- @panic "USER ???" If the number of codes exceeds Huffman::KMaxCodes
-*/
- {
- if(TUint(aNumCodes)>TUint(KMaxCodes))
- Panic(EHuffmanTooManyCodes);
-
- // Sort the values into decreasing order of frequency
- //
- TNode* nodes = new TNode[aNumCodes];
- if(nodes==NULL)
- Panic(EHuffmanOutOfMemory);
-
- TInt lCount=0;
-
- for (TInt ii=0;ii<aNumCodes;++ii)
- {
- TInt c=aFrequency[ii];
- if (c!=0)
- InsertInOrder(nodes,lCount++,c,ii|KLeaf);
- }
-
- // default code length is zero
- HMem::FillZ(aHuffman,aNumCodes*sizeof(TUint32));
-
- if (lCount==0)
- {
- // no codes with frequency>0. No code has a length
- }
- else if (lCount==1)
- {
- // special case for a single value (always encode as "0")
- aHuffman[nodes[0].iRight&~KLeaf]=1;
- }
- else
- {
- // Huffman algorithm: pair off least frequent nodes and reorder
- //
- do
- {
- --lCount;
- TUint c=nodes[lCount].iCount + nodes[lCount-1].iCount;
- nodes[lCount].iLeft=nodes[lCount-1].iRight;
- // re-order the leaves now to reflect new combined frequency 'c'
- InsertInOrder(nodes,lCount-1,c,lCount);
- } while (lCount>1);
- // generate code lengths in aHuffman[]
- HuffmanLengthsL(aHuffman,nodes,1,0);
- }
-
- delete [] nodes;
-
- if(!IsValid(aHuffman,aNumCodes))
- Panic(EHuffmanInvalidCoding);
- }
-
-TBool Huffman::IsValid(const TUint32 aHuffman[],TInt aNumCodes)
-/** Validate a Huffman encoding
-
- This verifies that a Huffman coding described by the code lengths is valid.
- In particular, it ensures that no code exceeds the maximum length and
- that it is possible to generate a canonical coding for the specified lengths.
-
- @param "const TUint32 aHuffman[]" The table of code lengths as generated by Huffman::HuffmanL()
- @param "TInt aNumCodes" The number of codes in the table
-
- @return True if the code is valid, otherwise false
-*/
- {
- // The code is valid if one of the following holds:
- // (a) the code exactly fills the 'code space'
- // (b) there is only a single symbol with code length 1
- // (c) there are no encoded symbols
- //
- TUint remain=1<<KMaxCodeLength;
- TInt totlen=0;
- for (const TUint32* p=aHuffman+aNumCodes; p>aHuffman;)
- {
- TInt len=*--p;
- if (len>0)
- {
- totlen+=len;
- if (len>KMaxCodeLength)
- return EFalse;
- TUint c=1<<(KMaxCodeLength-len);
- if (c>remain)
- return EFalse;
- remain-=c;
- }
- }
-
- return remain==0 || totlen<=1;
- }
-
-void Huffman::Encoding(const TUint32 aHuffman[],TInt aNumCodes,TUint32 aEncodeTable[])
-/** Create a canonical Huffman encoding table
-
- This generates the huffman codes used by TBitOutput::HuffmanL() to write huffman
- encoded data. The input is table of code lengths, as generated by Huffman::HuffmanL()
- and must represent a valid huffman code.
-
- @param "const TUint32 aHuffman[]" The table of code lengths as generated by Huffman::HuffmanL()
- @param "TInt aNumCodes" The number of codes in the table
- @param "TUint32 aEncodeTable[]" The table for the output huffman codes. This must be
- the same size as the code-length table, and can safely be the same table
-
- @panic "USER ???" If the provided code is not a valid Huffman coding
-
- @see IsValid()
- @see HuffmanL()
-*/
- {
- __ASSERT_ALWAYS(IsValid(aHuffman,aNumCodes),Panic(EHuffmanInvalidCoding));
-
- TFixedArray<TInt,KMaxCodeLength> lenCount;
- lenCount.Reset();
-
- TInt ii;
- for (ii=0;ii<aNumCodes;++ii)
- {
- TInt len=aHuffman[ii]-1;
- if (len>=0)
- ++lenCount[len];
- }
-
- TFixedArray<TUint,KMaxCodeLength> nextCode;
- TUint code=0;
- for (ii=0;ii<KMaxCodeLength;++ii)
- {
- code<<=1;
- nextCode[ii]=code;
- code+=lenCount[ii];
- }
-
- for (ii=0;ii<aNumCodes;++ii)
- {
- TInt len=aHuffman[ii];
- if (len==0)
- aEncodeTable[ii]=0;
- else
- {
- aEncodeTable[ii] = (nextCode[len-1]<<(KMaxCodeLength-len))|(len<<KMaxCodeLength);
- ++nextCode[len-1];
- }
- }
- }
-
-/** the encoding table for the externalised code
- @internal
-*/
-const TUint32 HuffmanEncoding[]=
- {
- 0x10000000,
- 0x1c000000,
- 0x12000000,
- 0x1d000000,
- 0x26000000,
- 0x26800000,
- 0x2f000000,
- 0x37400000,
- 0x37600000,
- 0x37800000,
- 0x3fa00000,
- 0x3fb00000,
- 0x3fc00000,
- 0x3fd00000,
- 0x47e00000,
- 0x47e80000,
- 0x47f00000,
- 0x4ff80000,
- 0x57fc0000,
- 0x5ffe0000,
- 0x67ff0000,
- 0x77ff8000,
- 0x7fffa000,
- 0x7fffb000,
- 0x7fffc000,
- 0x7fffd000,
- 0x7fffe000,
- 0x87fff000,
- 0x87fff800
- };
-
-void EncodeRunLengthL(TBitOutput& aOutput, TInt aLength)
-/** encode 0a as '0' and 0b as '1', return number of symbols created
-
- @internal
-*/
- {
- if (aLength>0)
- {
- EncodeRunLengthL(aOutput,(aLength-1)>>1);
- aOutput.HuffmanL(HuffmanEncoding[1-(aLength&1)]);
- }
- }
-
-void Huffman::ExternalizeL(TBitOutput& aOutput,const TUint32 aHuffman[],TInt aNumCodes)
-/** Store a canonical huffman encoding in compact form
-
- As the encoding is canonical, only the code lengths of each code needs to be saved.
-
- Due to the nature of code length tables, these can usually be stored very compactly
- by encoding the encoding itself, hence the use of the bit output stream.
-
- @param "TBitOutput& aOutput" The output stream for the encoding
- @param "const TUint32 aHuffman[]" The table of code lengths as generated by Huffman::HuffmanL()
- @param "TInt aNumCodes" The number of huffman codes in the table
-
- @leave "TBitOutput::HuffmanL()"
-*/
- {
- // We assume that the code length table is generated by the huffman generator,
- // in which case the maxmimum code length is 27 bits.
- //
- // We apply three transformations to the data:
- // 1. the data goes through a move-to-front coder
- // 2. apply a rle-0 coder which replace runs of '0' with streams of '0a' and '0b'
- // 3. encode the result using a predefined (average) huffman coding
- //
- // This can be done in a single pass over the data, avoiding the need for additional
- // memory.
- //
- // initialise the list for the MTF coder
- TFixedArray<TUint8,Huffman::KMetaCodes> list;
- TInt i;
- for (i=0;i<list.Count();++i)
- list[i]=TUint8(i);
- TInt last=0;
-
- TInt rl=0;
- const TUint32* p32=aHuffman;
- const TUint32* e32=p32+aNumCodes;
- while (p32<e32)
- {
- TInt c=*p32++;
- if (c==last)
- ++rl; // repeat of last symbol
- else
- {
- // encode run-length
- EncodeRunLengthL(aOutput,rl);
- rl=0;
- // find code in MTF list
- TInt j;
- for (j=1;list[j]!=c;++j)
- ;
- // store this code
- aOutput.HuffmanL(HuffmanEncoding[j+1]);
- // adjust list for MTF algorithm
- while (--j>0)
- list[j+1]=list[j];
- list[1]=TUint8(last);
- last=c;
- }
- }
- // encod any remaining run-length
- EncodeRunLengthL(aOutput,rl);
- }
-
-
-TBitOutput::TBitOutput()
-/** Construct a bit stream output object
-
- Following construction the bit stream is ready for writing bits, but will first call
- OverflowL() as the output buffer is 'full'. A derived class can detect this state as
- Ptr() will return null.
-*/
- :iCode(0),iBits(-8),iPtr(0),iEnd(0)
- {}
-
-TBitOutput::TBitOutput(TUint8* aBuf,TInt aSize)
-/** Construct a bit stream output object over a buffer
-
- Data will be written to the buffer until it is full, at which point OverflowL() will
- be called. This should handle the data and then can Set() again to reset the buffer
- for further output.
-
- @param "TUint8* aBuf" The buffer for output
- @param "TInt aSize" The size of the buffer in bytes
-*/
- :iCode(0),iBits(-8),iPtr(aBuf),iEnd(aBuf+aSize)
- {}
-
-void TBitOutput::HuffmanL(TUint aHuffCode)
-/** Write a huffman code
-
- This expects a huffman code value as generated by Huffman::Encoding()
-
- @param "TUint aHuffCode" The huffman code write to the stream
-
- @leave "OverflowL()" If the output buffer is full, OverflowL() is called
-*/
- {
- DoWriteL(aHuffCode<<(32-Huffman::KMaxCodeLength),aHuffCode>>Huffman::KMaxCodeLength);
- }
-
-void TBitOutput::WriteL(TUint aValue,TInt aLength)
-/** Write an arbitrary integer value
-
- Write an unsigned integer using the number of bits specified. Only
- the low order bits of the value are written to the output, most
- significant bit first.
-
- @param "TUint aValue" The value to write to the stream
- @param "TUint aLength" The number of bits to output
-
- @leave "OverflowL()" If the output buffer is full, OverflowL() is called
-*/
- {
- if (aLength)
- DoWriteL(aValue<<=32-aLength,aLength);
- }
-
-void TBitOutput::PadL(TUint aPadding)
-/** Pad the bitstream to the next byte boundary
-
- Terminate the bitstream by padding the last byte with the requested value.
- Following this operation the bitstream can continue to be used, the data will
- start at the next byte.
-
- @param "TUint aPadding" The bit value to pad the final byte with
-
- @leave "OverflowL()" If the output buffer is full, OverflowL() is called
-*/
- {
- if (iBits>-8)
- WriteL(aPadding?0xffffffffu:0,-iBits);
- }
-
-void TBitOutput::DoWriteL(TUint aBits,TInt aSize)
-/** Write the higher order bits to the stream
-
- @internal
-*/
- {
- if (aSize>25)
- {
- // cannot process >25 bits in a single pass
- // so do the top 8 bits first
- ASSERT(aSize<=32);
- DoWriteL(aBits&0xff000000u,8);
- aBits<<=8;
- aSize-=8;
- }
-
- TInt bits=iBits;
- TUint code=iCode|(aBits>>(bits+8));
- bits+=aSize;
- if (bits>=0)
- {
- TUint8* p=iPtr;
- do
- {
- if (p==iEnd)
- {
- // run out of buffer space so invoke the overflow handler
- iPtr=p;
- OverflowL();
- p=iPtr;
- ASSERT(p!=iEnd);
- }
- *p++=TUint8(code>>24);
- code<<=8;
- bits-=8;
- } while (bits>=0);
- iPtr=p;
- }
- iCode=code;
- iBits=bits;
- }
-
-void TBitOutput::OverflowL()
-/** Handle a full output buffer
-
- This virtual function is called when the output buffer is full. It should deal
- with the data in the buffer before reseting the buffer using Set(), allowing
- further data to be written.
-
- A derived class can replace this to write the data to a file (for example)
- before marking the buffer as empty.
-
- @leave "KErrOverflow" The default implementation leaves
-*/
- {
- Panic(EHuffmanBufferOverflow);
- }