--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/mmplugins/imagingplugins/codecs/JPEGCodec/JPGHUFF.CPP Tue Feb 02 01:56:55 2010 +0200
@@ -0,0 +1,448 @@
+// Copyright (c) 1997-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:
+//
+
+#include <e32base.h>
+
+#include "JpegTypes.h"
+
+/**
+ @file
+ @internalComponent
+*/
+
+// THuffmanTable
+THuffmanTable::THuffmanTable():
+ iLastCode(0),
+ iState(EUnInitialised)
+ {
+ // current implementation doesn't support more than 8 bit
+ ASSERT(KJpgHuffmanLookAhead <= sizeof(TUint8)*8 );
+ }
+
+TInt THuffmanTable::SetL(const TUint8* aData, const TUint8* aDataLimit)
+ {
+ //We assume that a complete table is passed
+ //If there is not enougth data the table is corrupt
+ if(aData+KJpgHuffmanTableBitsSize > aDataLimit)
+ {
+ User::Leave(KErrCorrupt);
+ }
+
+ Mem::Copy(iBits,aData,KJpgHuffmanTableBitsSize);
+ aData += KJpgHuffmanTableBitsSize;
+
+ TInt valuesSize = 0;
+ for (TInt count = 0; count < KJpgHuffmanTableBitsSize; count++)
+ {
+ valuesSize += iBits[count];
+ }
+
+ if((valuesSize <= 0) || (valuesSize > KJpgHuffmanTableSize) || (aData+valuesSize > aDataLimit))
+ {
+ User::Leave(KErrCorrupt);
+ }
+
+ Mem::Copy(iValues,aData,valuesSize);
+ Mem::FillZ(iValues + valuesSize,KJpgHuffmanTableSize - valuesSize);
+
+ SetState(EInitialised);
+
+ return KJpgHuffmanTableBitsSize + valuesSize;
+ }
+
+TInt THuffmanTable::GetL(TUint8* aData)
+ {
+ Mem::Copy(aData,iBits,KJpgHuffmanTableBitsSize);
+ aData += KJpgHuffmanTableBitsSize;
+
+ TInt valuesSize = 0;
+ for (TInt count = 0; count < KJpgHuffmanTableBitsSize; count++)
+ {
+ valuesSize += iBits[count];
+ }
+
+ if ((valuesSize <= 0) || (valuesSize > KJpgHuffmanTableSize))
+ {
+ User::Leave(KErrCorrupt);
+ }
+
+ Mem::Copy(aData,iValues,valuesSize);
+
+ return KJpgHuffmanTableBitsSize + valuesSize;
+ }
+
+void THuffmanTable::GenerateSizes(THuffmanCode* aCode)
+ {
+ TInt i = 0;
+ TInt j = 1;
+ TInt k = 0;
+
+ while (i < KJpgHuffmanTableBitsSize)
+ {
+ if (j > iBits[i])
+ {
+ i++;
+ j = 1;
+ }
+ else
+ {
+ if (k == KJpgHuffmanTableSize - 1 )
+ {
+ break; // to prevent table overrun by a malicious image
+ }
+ aCode[k].iSize = i + 1;
+ k++;
+ j++;
+ }
+ }
+
+ aCode[k].iSize = 0;
+ iLastCode = k - 1;
+ }
+
+void THuffmanTable::GenerateCodes(THuffmanCode* aCode)
+ {
+ TInt k = 0;
+ TUint16 code = 0;
+ TInt si = aCode[0].iSize;
+
+ FOREVER
+ {
+ do {
+ aCode[k].iCode = code;
+ aCode[k].iValue = iValues[k];
+ code++;
+ k++;
+ }
+ while (aCode[k].iSize == si);
+
+ if (aCode[k].iSize == 0 || k > iLastCode)
+ {
+ break;
+ }
+
+ do {
+ code <<= 1;
+ si++;
+ }
+ while (aCode[k].iSize != si || si > KJpgHuffmanTableBitsSize);
+ }
+ }
+/**
+ Implemetation of TKey parameter class
+ for use in User::QuickSort.
+ Sort by "iValue" member of the THuffmanTable::THuffmanCode
+*/
+class THuffmanValueKey : public TKey
+ {
+public:
+ explicit THuffmanValueKey(THuffmanTable::THuffmanCode* aArray);
+ TInt Compare(TInt aLeft, TInt aRight) const;
+ TAny *At(TInt anIndex) const;
+protected:
+ THuffmanTable::THuffmanCode* iArray;
+ };
+
+inline
+THuffmanValueKey::THuffmanValueKey(THuffmanTable::THuffmanCode* aArray)
+ {
+ iArray = aArray;
+ }
+
+TInt THuffmanValueKey::Compare(TInt aLeft, TInt aRight) const
+ {
+ return iArray[aLeft].iValue - iArray[aRight].iValue;
+ }
+
+TAny* THuffmanValueKey::At(TInt anIndex) const
+ {
+ return iArray + anIndex;
+ }
+
+/**
+ Implemetation of TKey parameter class
+ for use in User::QuickSort.
+ Sort by "iIndex" member of the THuffmanTable::THuffmanCode
+*/
+class THuffmanIndexKey : public TKey
+ {
+public:
+ explicit THuffmanIndexKey(THuffmanTable::THuffmanCode* aArray);
+ TInt Compare(TInt aLeft, TInt aRight) const;
+ TAny *At(TInt anIndex) const;
+protected:
+ THuffmanTable::THuffmanCode* iArray;
+ };
+
+inline
+THuffmanIndexKey::THuffmanIndexKey(THuffmanTable::THuffmanCode* aArray)
+ {
+ iArray = aArray;
+ }
+
+TInt THuffmanIndexKey::Compare(TInt aLeft, TInt aRight) const
+ {
+ return iArray[aLeft].iIndex - iArray[aRight].iIndex;
+ }
+
+TAny* THuffmanIndexKey::At(TInt anIndex) const
+ {
+ return iArray + anIndex;
+ }
+
+/**
+ Implemetation of TSwap parameter class
+ for use in User::QuickSort.
+ Swaps two THuffmanTable::THuffmanCode variables
+*/
+class THuffmanCodeSwap : public TSwap
+ {
+public:
+ explicit THuffmanCodeSwap(THuffmanTable::THuffmanCode* aArray);
+ void Swap(TInt aLeft, TInt aRight) const;
+protected:
+ THuffmanTable::THuffmanCode* iArray;
+ };
+
+inline
+THuffmanCodeSwap::THuffmanCodeSwap(THuffmanTable::THuffmanCode* aArray)
+ {
+ iArray = aArray;
+ }
+
+void THuffmanCodeSwap::Swap(TInt aLeft, TInt aRight) const
+ {
+ THuffmanTable::THuffmanCode tmp=iArray[aLeft];
+ iArray[aLeft] = iArray[aRight];
+ iArray[aRight] = tmp;
+ }
+
+void THuffmanTable::SortByCode(THuffmanTable::THuffmanCode* aCode, TUint8* aBitsToCodeIdxHash)
+ {
+ for (TInt count = 0; count <= iLastCode; count++)
+ {
+ THuffmanCode& codeEntry = aCode[count];
+ aCode[count].iIndex = (1 << codeEntry.iSize) - 1 + codeEntry.iCode;
+ }
+
+ THuffmanIndexKey key(aCode);
+ THuffmanCodeSwap swap(aCode);
+ User::QuickSort(iLastCode+1, key, swap);
+
+ aBitsToCodeIdxHash[0]=0;
+ TInt sz=0;
+ for (TInt j=0; j <= iLastCode; ++j)
+ {
+ if (aCode[j].iSize > sz)
+ {
+ TInt k=sz+1;
+ sz = aCode[j].iSize;
+ for (; k<=sz; ++k)
+ {
+ aBitsToCodeIdxHash[k]=j;
+ }
+ }
+ }
+ aBitsToCodeIdxHash[sz+1]=iLastCode;
+ }
+
+class THuffmanValueSwap : public TSwap
+ {
+public:
+ explicit THuffmanValueSwap(THuffmanTable::THuffmanCode* aArray);
+ void Swap(TInt aLeft, TInt aRight) const;
+protected:
+ THuffmanTable::THuffmanCode* iArray;
+ };
+
+inline
+THuffmanValueSwap::THuffmanValueSwap(THuffmanTable::THuffmanCode* aArray)
+ {
+ iArray = aArray;
+ }
+
+void THuffmanValueSwap::Swap(TInt aLeft, TInt aRight) const
+ {
+ THuffmanTable::THuffmanCode tmp=iArray[aLeft];
+ iArray[aLeft] = iArray[aRight];
+ iArray[aRight] = tmp;
+ }
+
+
+void THuffmanTable::SortByValue(THuffmanTable::THuffmanCode* aArray)
+ {
+ THuffmanValueKey key(aArray);
+ THuffmanValueSwap swap(aArray);
+ User::QuickSort(iLastCode+1, key, swap);
+ }
+
+void TDecHuffmanTable::MakeDerivedTableL()
+ {
+ if(State()!=EInitialised)
+ {
+ return;
+ }
+
+ THuffmanCode* codes = (THuffmanCode*)User::AllocZ(KJpgHuffmanTableSize*sizeof(THuffmanCode));
+ if (codes == NULL)
+ {
+ User::Leave(KErrNoMemory);
+ }
+
+ CleanupStack::PushL(codes);
+
+ Mem::FillZ(iLookupTable, KJpgHuffmanTableSize * sizeof(TUint16));
+ Mem::FillZ(iValue, KJpgHuffmanTableSize * sizeof(TUint16));
+ Mem::FillZ(iIndex, KJpgHuffmanTableSize * sizeof(TInt));
+
+ GenerateSizes(codes);
+
+ if (iLastCode < 0 || iLastCode >= KJpgHuffmanTableSize)
+ {
+ User::Leave(KErrCorrupt);
+ }
+
+ GenerateCodes(codes);
+
+ TInt p = 0;
+ for (TUint l = 1; l <= KJpgHuffmanLookAhead; l++)
+ {
+ for (TUint i = 1; i <= iBits[l-1]; i++, p++)
+ {
+ // l = current code's length, p = its index in huffcode[] & huffval[].
+ // Generate left-justified code followed by all possible bit sequences
+ TInt lookbits = codes[p].iCode << (KJpgHuffmanLookAhead-l);
+ for (TInt ctr = 1 << (KJpgHuffmanLookAhead-l); ctr > 0; ctr--)
+ {
+ iLookupTable[lookbits] = ((l << 8) | iValues[p]);
+ lookbits++;
+ }
+ }
+ }
+
+ SortByCode(codes, iBitsToCodeIdxHash);
+
+ for (TInt i = 0; i < iLastCode+1; i++)
+ {
+ iValue[i] = codes[i].iValue;
+ iIndex[i] = codes[i].iIndex;
+ }
+
+ CleanupStack::PopAndDestroy();
+ SetState(EParsed);
+ }
+
+template <TInt aTableSize> void TEncHuffmanTable<aTableSize>::MakeDerivedTableL()
+ {
+ if(State()!=EInitialised)
+ {
+ return;
+ }
+
+ THuffmanCode* codes = (THuffmanCode*)User::AllocZ(KJpgHuffmanTableSize*sizeof(THuffmanCode));
+ if (codes == NULL)
+ {
+ User::Leave(KErrNoMemory);
+ }
+
+ CleanupStack::PushL(codes);
+
+ Mem::FillZ(codes, KJpgHuffmanTableSize * sizeof(THuffmanCode));
+ Mem::FillZ(iLookupTable, aTableSize * sizeof(TUint32));
+
+ GenerateSizes(codes);
+
+ if (iLastCode < 0 || iLastCode >= KJpgHuffmanTableSize)
+ {
+ User::Leave(KErrCorrupt);
+ }
+
+ GenerateCodes(codes);
+ SortByValue(codes);
+
+ for (TInt i=iLastCode; i; --i)
+ {
+ ASSERT( codes[i].iValue <= aTableSize );
+ codes[codes[i].iValue] = codes[i];
+ }
+
+ for (TInt i=0; i<=iLastCode; i++)
+ {
+ TInt value = iValues[i];
+ iLookupTable[value] = (codes[value].iSize | (codes[value].iCode << 16));
+ }
+
+ CleanupStack::PopAndDestroy();
+ SetState(EParsed);
+ }
+
+const TInt KEncDCHTSize = 11;// the defines from jpegwritecodec.h
+const TInt KEncACHTSize = 0xFA;
+
+template class TEncHuffmanTable<KEncDCHTSize+1>;
+template class TEncHuffmanTable<KEncACHTSize+1>; //templates for jpegwritecodec
+
+void THuffmanTableProcessor::ProcessHuffmanTableL(const TUint8*& aDataPtr, const TUint8* aDataPtrLimit, TDecHuffmanTable* aDCTable, TDecHuffmanTable* aACTable)
+ {
+ while (aDataPtr < aDataPtrLimit)
+ {
+ TInt index = *aDataPtr++;
+ TBool dcTable = !(index & 0x10);
+ index &= 0x0f;
+ if (index >= KJpgMaxNumberOfTables)
+ User::Leave(KErrCorrupt);
+ TDecHuffmanTable& table = dcTable ? aDCTable[index] : aACTable[index];
+ aDataPtr += table.SetL(aDataPtr, aDataPtrLimit);
+ }
+ //The block length and actual data did not match
+ if(aDataPtr != aDataPtrLimit)
+ User::Leave(KErrCorrupt);
+ }
+
+/**
+ Before calling this function, the Huffman tables should be set.
+ */
+void TJpgScanInfoProcessor::ProcessStartOfScanL(const TUint8*& aPtr, const TJpgFrameInfo& aJpgFrameInfo, TJpgScanInfo& aScanInfo, TDecHuffmanTable* aDCTable, TDecHuffmanTable* aACTable)
+ {
+ aScanInfo.iNumberOfComponents = *aPtr++;
+
+ //At least one component and not more than specified in the start of frame header
+ if(aScanInfo.iNumberOfComponents < KJpgMinNumberOfComponents || aScanInfo.iNumberOfComponents > aJpgFrameInfo.iNumberOfComponents)
+ User::Leave(KErrCorrupt);
+
+ for (TInt count = 0; count < aScanInfo.iNumberOfComponents; count++)
+ {
+ aScanInfo.iComponent[count].iId = *aPtr++;
+
+ TUint8 table = *aPtr++;
+ TUint8 DCTable = static_cast<TUint8>(table >> 4);
+ TUint8 ACTable = static_cast<TUint8>(table & 0x0f);
+
+ if(DCTable > KJpgMaxNumberOfTables || ACTable > KJpgMaxNumberOfTables)
+ User::Leave(KErrCorrupt);
+
+ aScanInfo.iComponent[count].iDCCodingTable = DCTable;
+ aScanInfo.iComponent[count].iACCodingTable = ACTable;
+
+ aDCTable[DCTable].MakeDerivedTableL();
+ aACTable[ACTable].MakeDerivedTableL();
+ }
+
+ aScanInfo.iStartSpectralSelection = *aPtr++;
+ aScanInfo.iEndSpectralSelection = *aPtr++;
+ TUint8 successiveApproximation = *aPtr;
+ aScanInfo.iSuccessiveApproximationBitsHigh = successiveApproximation >> 4;
+ aScanInfo.iSuccessiveApproximationBitsLow = successiveApproximation & 0x0f;
+ }