--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/imagingmodules/jp2kcodec/Src/JP2KCodec.cpp Thu Dec 17 09:22:31 2009 +0200
@@ -0,0 +1,2751 @@
+/*
+* Copyright (c) 2003-2006 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: CJp2kReadCodec class implements the ICL read codec interface.
+*
+*/
+
+
+// INCLUDE FILES
+#include <fbs.h>
+#include <JP2KImageData.h>
+#include "JP2KImageUtils.h"
+#include "JP2KFormat.h"
+#include "JP2KStreamReader.h"
+#include "JP2KTileInfo.h"
+#include "JP2KImageInfo.h"
+#include "JP2KCodec.h"
+#include "JP2KEntropyDecoder.h"
+#include "JP2KImageWriter.h"
+#include "JP2KSynthesis.h"
+
+// EXTERNAL DATA STRUCTURES
+
+// EXTERNAL FUNCTION PROTOTYPES
+
+// CONSTANTS
+
+// MACROS
+
+// LOCAL CONSTANTS AND MACROS
+
+// MODULE DATA STRUCTURES
+
+// LOCAL FUNCTION PROTOTYPES
+
+// FORWARD DECLARATIONS
+
+// ============================= LOCAL FUNCTIONS ===============================
+
+// ============================ MEMBER FUNCTIONS ===============================
+
+// -----------------------------------------------------------------------------
+// CJp2kReadCodec::NewL
+// Two-phased constructor.
+// -----------------------------------------------------------------------------
+//
+CJp2kReadCodec* CJp2kReadCodec::NewL( const TJ2kInfo& aJ2kInfo )
+ {
+ CJp2kReadCodec* self = new ( ELeave ) CJp2kReadCodec( aJ2kInfo );
+
+ CleanupStack::PushL( self );
+ self->ConstructL();
+ CleanupStack::Pop( self );
+
+ return self;
+ }
+
+// Destructor
+CJp2kReadCodec::~CJp2kReadCodec()
+ {
+ delete iImageInfo;
+ iImageInfo = 0;
+
+ delete iEntropy;
+ iEntropy = 0;
+
+ delete iImageWriter;
+ iImageWriter = 0;
+
+ delete iSynthesis;
+ iSynthesis = 0;
+ }
+
+// -----------------------------------------------------------------------------
+// CJp2kReadCodec::DecodeTileL
+// Decoding the current tile-part
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+TFrameState CJp2kReadCodec::DecodeTileL()
+ {
+ CJ2kTileInfo& tile = CONST_CAST( CJ2kTileInfo&, iImageInfo->TileAt( iLastTileIndex ) );
+
+ // Decode and delete the tile
+ DecodeAndDeleteTileL( tile );
+
+ // reset the codec back to the parsing state
+ iDecodeTile = EFalse;
+ TFrameState retCode = EFrameIncomplete;
+
+ // Start with new tile
+ iUseNewTile = ETrue;
+ if ( !iUseNextTile )
+ {
+ iFHState = EStateInUnknown;
+ retCode = EFrameIncompleteRepositionRequest;
+ }
+ else
+ {
+ if ( !iSequential )
+ {
+ // Must be End of Codestream EOC
+ iFHState = EStateInEOC;
+ retCode = EFrameComplete;
+ }
+ else if ( iFHState == EStateInEOC )
+ {
+ retCode = EFrameComplete;
+ }
+ else
+ {
+ iFHState = EStateInUnknown;
+ }
+ }
+ return retCode;
+ }
+
+// -----------------------------------------------------------------------------
+// CJp2kReadCodec::IsDecodeTile
+// Is codec in the decoding state
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+TBool CJp2kReadCodec::IsDecodeTile() const
+ {
+ return iDecodeTile;
+ }
+
+// -----------------------------------------------------------------------------
+// CJp2kReadCodec::InitFrameHeader
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+void CJp2kReadCodec::InitFrameHeader( TFrameInfo& aFrameInfo, CFrameImageData& aFrameData )
+ {
+ // Initialize internal data structure for holding frame header
+ ASSERT( aFrameInfo.CurrentFrameState() == TFrameInfo::EFrameInfoUninitialised );
+
+ iFrame = &aFrameInfo;
+ iFrameData = &aFrameData;
+ aFrameInfo.SetCurrentFrameState( TFrameInfo::EFrameInfoProcessingFrameHeader );
+ }
+
+// -----------------------------------------------------------------------------
+// CJp2kReadCodec::ProcessFrameHeaderL
+// Collect the JP2 codestream Main Header information.
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+TFrameState CJp2kReadCodec::ProcessFrameHeaderL( TBufPtr8& aData )
+ {
+ // Read frame header and fill up internal data structure
+ TFrameState retCode = EFrameIncomplete;
+
+ iReader.iPtr = aData.Ptr();
+ iReader.iPtrStart = CONST_CAST( TUint8*, iReader.iPtr );
+ iReader.iPtrEnd = iReader.iPtrStart + aData.Length();
+
+ while ( iFHState != EStateInSOT )
+ {
+ iReader.iPtrStartMarker = CONST_CAST( TUint8*, iReader.iPtr );
+ switch ( iFHState )
+ {
+ case EStateInSOC:
+ {
+ retCode = ReadSOCL();
+ break;
+ }
+ case EStateInSIZ:
+ {
+ retCode = ReadSIZL();
+ break;
+ }
+ case EStateInCOD:
+ {
+ retCode = ReadCODL();
+ break;
+ }
+ case EStateInCOC:
+ {
+ retCode = ReadCOCL();
+ break;
+ }
+ case EStateInQCD:
+ {
+ retCode = ReadQCDL();
+ break;
+ }
+ case EStateInQCC:
+ {
+ retCode = ReadQCCL();
+ break;
+ }
+ case EStateInRGN:
+ {
+ retCode = ReadRGNL();
+ break;
+ }
+ case EStateInPOC:
+ {
+ retCode = ReadPOCL();
+ break;
+ }
+ case EStateInPPM:
+ {
+ retCode = ReadPPML();
+ break;
+ }
+ case EStateInTLM:
+ {
+ retCode = ReadTLML();
+ break;
+ }
+ case EStateInPLM:
+ {
+ retCode = ReadPLML();
+ break;
+ }
+ case EStateInCRG:
+ {
+ retCode = ReadCRGL();
+ break;
+ }
+ case EStateInCOM:
+ {
+ retCode = ReadCOML();
+ break;
+ }
+ case EStateInUnknown:
+ {
+ // Update the internal state based on the Marker
+ retCode = UpdateStateFromMarkerL();
+ break;
+ }
+ default:
+ {
+ // Unrecognized marker
+ User::Leave( KErrCorrupt );
+ break;
+ }
+ }
+ // Check for underflow
+ if ( retCode != EFrameComplete )
+ {
+ aData.Shift( iReader.iPtr - iReader.iPtrStart );
+ return retCode;
+ }
+
+ // Update the internal counter for data processed
+ iReader.UpdateMainHeader();
+ }
+
+ // Convert the MainHeader's COM marker to TJp2kComment
+ // and let the framework managing the buffer.
+ TMainMarker& mainMarker = CONST_CAST( TMainMarker&, iImageInfo->MainMarker() );
+ for ( TInt index = 0; index < mainMarker.iCom.Count(); ++index )
+ {
+ TJp2kComment* jp2kComment = new ( ELeave ) TJp2kComment;
+ CleanupDeletePushL( jp2kComment );
+
+ jp2kComment->iComment = mainMarker.iCom[index]->iCcom;
+
+ User::LeaveIfError( iFrameData->AppendImageData( jp2kComment ) );
+ CleanupStack::Pop();
+
+ // Transfer the ownership of the buffer from TMainMarker to framework
+ User::LeaveIfError( iFrameData->AppendImageBuffer( jp2kComment->iComment ) );
+ mainMarker.iCom[index]->iCcom = 0;
+ }
+
+ // Convert some metadata from file format to TImageDataBlock derived objects
+ ConvertImageDataL();
+
+ // Try to sort PPM and PLM if there is one
+ iImageInfo->DoCompactMainHeaderL();
+
+ aData.Shift( iReader.iPtr - iReader.iPtrStart );
+
+ // Fill up the image related information if it is not
+ // JP2 file format
+ if ( !( iJ2kInfo.iOption & TJ2kInfo::EJP2file ) )
+ {
+ const TSizMarker &sizMarker = iImageInfo->SizMarker();
+
+ // To get the right output image size, we must compute the size tile by tile.
+ // Compute the width of the output image
+ TInt32 tileCompCanvasWidth = 0;
+ TInt32 numHorTiles = iImageInfo->NumOfHorizTiles();
+ TInt32 tileStartCanvas;
+ TInt32 tileEndCanvas;
+ TInt32 tileCompStartCanvas;
+ for(TUint16 indexX = 0; indexX < numHorTiles; ++indexX )
+ {
+ tileStartCanvas = Max( ( sizMarker.iXTOsiz + indexX * sizMarker.iXTsiz ), sizMarker.iXOsiz );
+ tileEndCanvas = Min( ( sizMarker.iXTOsiz + ( indexX + 1 ) * sizMarker.iXTsiz ), sizMarker.iXsiz );
+
+ // Add this tile's contribution to the total size
+ tileCompStartCanvas = TJ2kUtils::Ceil( tileStartCanvas, sizMarker.iXRsiz[0] );
+ tileCompCanvasWidth += TJ2kUtils::Ceil( tileEndCanvas, sizMarker.iXRsiz[0] ) - tileCompStartCanvas;
+ }
+
+ // Compute the height of the output image
+ TInt32 tileCompCanvasHeight = 0;
+ TInt32 numVerTiles = iImageInfo->NumOfVertTiles();
+ for(TUint16 indexY = 0; indexY < numVerTiles; ++indexY )
+ {
+ tileStartCanvas = Max( ( sizMarker.iYTOsiz + indexY * sizMarker.iYTsiz ), sizMarker.iYOsiz );
+ tileEndCanvas = Min( ( sizMarker.iYTOsiz + ( indexY + 1 ) * sizMarker.iYTsiz ), sizMarker.iYsiz );
+
+ // Add this tile's contribution to the total size
+ tileCompStartCanvas = TJ2kUtils::Ceil( tileStartCanvas, sizMarker.iYRsiz[0] );
+ tileCompCanvasHeight += TJ2kUtils::Ceil( tileEndCanvas, sizMarker.iYRsiz[0] ) - tileCompStartCanvas;
+ }
+
+ iFrame->iOverallSizeInPixels = TSize( tileCompCanvasWidth, tileCompCanvasHeight );
+
+ iFrame->iFrameCoordsInPixels.SetRect( TPoint( 0, 0 ), iFrame->iOverallSizeInPixels );
+ iFrame->iFrameSizeInTwips.SetSize( 0, 0 );
+
+ for ( TUint16 index = 0; index < sizMarker.iCsiz; ++index )
+ {
+ iFrame->iBitsPerPixel += ( ( sizMarker.iSsiz[index] & 0x7f ) + 1 );
+ }
+
+ // We can dither.
+ iFrame->iFlags |= TFrameInfo::ECanDither;
+
+ // Decoder is able to handle scaleable resolution
+ iFrame->iFlags |= TFrameInfo::EConstantAspectRatio;
+
+ if ( sizMarker.iCsiz > 1 )
+ {
+ iFrame->iFlags |= TFrameInfo::EColor;
+ }
+
+ // Animation is not allowed
+ iFrame->iDelay = 0;
+
+ switch ( iFrame->iBitsPerPixel )
+ {
+ case 1:
+ {
+ iFrame->iFrameDisplayMode = EGray2;
+ break;
+ }
+ case 2:
+ {
+ iFrame->iFrameDisplayMode = EGray4;
+ break;
+ }
+ case 4:
+ {
+ iFrame->iFrameDisplayMode = ( iFrame->iFlags & TFrameInfo::EColor ) ? EColor16 : EGray16;
+ break;
+ }
+ case 8:
+ {
+ iFrame->iFrameDisplayMode = ( iFrame->iFlags & TFrameInfo::EColor ) ? EColor16M : EGray256;
+ break;
+ }
+ case 12:
+ {
+ iFrame->iFrameDisplayMode = ( iFrame->iFlags & TFrameInfo::EColor ) ? EColor4K : EGray256;
+ break;
+ }
+ case 16:
+ {
+ iFrame->iFrameDisplayMode = EColor64K;
+ break;
+ }
+ case 24:
+ {
+ iFrame->iFrameDisplayMode = EColor16M;
+ break;
+ }
+ default:
+ {
+ iFrame->iFrameDisplayMode = EColor64K;
+ break;
+ }
+ }
+ }
+
+ // It is the offset that ICL framework used to read in
+ // more data from the image file.
+ iFrame->SetFrameDataOffset( iReader.iStartSOT );
+
+ // Frame header has been processed without error
+ // the flag is used by the ICL framework to determine
+ // whether it should continue processing or halt with error
+ iFrame->SetCurrentFrameState( TFrameInfo::EFrameInfoProcessingComplete );
+
+ return retCode;
+ }
+
+// -----------------------------------------------------------------------------
+// CJp2kReadCodec::InitFrameL
+// Called from ICL framework to initialise frame.
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+void CJp2kReadCodec::InitFrameL( TFrameInfo& /*aFrameInfo*/, CFrameImageData& /*aFrameData*/,
+ TBool aDisableErrorDiffusion, CFbsBitmap& aDestination,
+ CFbsBitmap* /*aDestinationMask*/ )
+ {
+ // Always use ERgb mode unless specified in the JP2 file format
+ TDisplayMode mode = ERgb;
+
+ TInt reductionFactor = ImageProcessorUtility::ReductionFactor( iFrame->iOverallSizeInPixels,
+ aDestination.SizeInPixels() );
+
+ iImageInfo->SetLevelDrop( (TUint8)reductionFactor );
+
+ // If the codestream doesn't contain enough wavelet levels to do the resolution
+ // reduction required by the framework / calling application, "extraLevels" are
+ // assigned to perform the resolution reduction. The "extra" resolution drop is
+ // performed at the output stage, i.e. all the samples are decoded, but only
+ // 1/4, 1/16, etc. are written to output.
+ if(reductionFactor > iImageInfo->MainMarker().iCod.iNumOfLevels)
+ {
+ iImageInfo->SetExtraLevelDrop( (TUint8)(reductionFactor - iImageInfo->MainMarker().iCod.iNumOfLevels) );
+ }
+ else
+ {
+ iImageInfo->SetExtraLevelDrop( 0 );
+ }
+
+ CImageProcessor* imageProc = ImageProcessorUtility::NewImageProcessorL( aDestination,
+ 0,
+ mode,
+ aDisableErrorDiffusion );
+ TPoint startAt( iFrame->iFrameCoordsInPixels.iTl.iX,
+ iFrame->iFrameCoordsInPixels.iTl.iY );
+
+ TRect imageSize( startAt, aDestination.SizeInPixels() );
+
+ // Prepare the bitmap using the image size
+ SetImageProcessor( imageProc );
+ imageProc->PrepareL( aDestination, imageSize );
+
+ // Clear bitmap so sensibly draw partial decodes
+ ClearBitmapL(aDestination, KRgbWhite);
+
+ iUseNewTile = ETrue;
+ iReader.iNewDataStart = iFrame->FrameDataOffset();
+ iStyleUsed = EUnknownDecoder;
+
+ iProgressBar = EFalse;
+ if ( ( iImageInfo->NumOfHorizTiles() == 1 ) &&
+ ( iImageInfo->NumOfVertTiles() == 1 ) )
+ {
+ // To force a return immediately from ProcessFrameL()
+ // on first entry to stimulate the occurrance of
+ // the progress bar
+ iProgressBar = ETrue;
+ }
+
+ if ( iFHState != EStateInSOT )
+ {
+ // We are in zoom in mode
+ iUseNextTile = iSequential = EFalse;
+ iFHState = EStateInSOT;
+ iLastTileIndex = 0;
+ iImageInfo->SetLastTilePartProcessed( (TUint16)0xffff );
+ iImageWriter->SetNewImageProcessor( imageProc );
+
+ if ( iJ2kInfo.iOption & TJ2kInfo::EJP2file )
+ {
+ iReader.iCSLength = iJ2kInfo.iCSBoxLength;
+
+ // We have read in all header information, so skip it
+ if ( iReader.iCSLength > iReader.iStartSOT )
+ {
+ iReader.iCSLength -= iReader.iStartSOT;
+ }
+ iReader.iDataUsed = 0;
+ }
+ }
+ }
+
+// -----------------------------------------------------------------------------
+// CJp2kReadCodec::ProcessFrameL
+// Collect the JP2 codestream Tile Part information.
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+TFrameState CJp2kReadCodec::ProcessFrameL(TBufPtr8& aSrc)
+ {
+ // Start decoding the compressed data stream
+ TFrameState retCode = EFrameIncomplete;
+
+ iReader.iPtr = aSrc.Ptr();
+
+ iReader.iPtrStart = CONST_CAST( TUint8*, iReader.iPtr );
+ iReader.iPtrEnd = iReader.iPtrStart + aSrc.Length();
+
+ while ( iFHState != EStateInEOC )
+ {
+ iReader.iPtrStartMarker = CONST_CAST( TUint8*, iReader.iPtr );
+ switch ( iFHState )
+ {
+ case EStateInSOT:
+ {
+ retCode = ReadSOTL();
+ break;
+ }
+ case EStateInSOD:
+ {
+ retCode = ReadSODL();
+ break;
+ }
+ case EStateInBITSTREAM:
+ {
+ retCode = ReadBitStreamL();
+ break;
+ }
+ case EStateInCOD:
+ {
+ retCode = ReadCODL( EFalse );
+ break;
+ }
+ case EStateInCOC:
+ {
+ retCode = ReadCOCL( EFalse );
+ break;
+ }
+ case EStateInQCD:
+ {
+ retCode = ReadQCDL( EFalse );
+ break;
+ }
+ case EStateInQCC:
+ {
+ retCode = ReadQCCL( EFalse );
+ break;
+ }
+ case EStateInRGN:
+ {
+ retCode = ReadRGNL( EFalse );
+ break;
+ }
+ case EStateInPOC:
+ {
+ retCode = ReadPOCL( EFalse );
+ break;
+ }
+ case EStateInPPT:
+ {
+ retCode = ReadPPTL();
+ break;
+ }
+ case EStateInPLT:
+ {
+ retCode = ReadPLTL();
+ break;
+ }
+ case EStateInCOM:
+ {
+ retCode = ReadCOML( EFalse );
+ break;
+ }
+ case EStateInUnknown:
+ {
+ // Update the internal state based on the Marker
+ retCode = UpdateStateFromMarkerL();
+ break;
+ }
+ case EStateInSkipTile:
+ {
+ retCode = ReadSkipTileL();
+ break;
+ }
+ default:
+ {
+ // Unrecognized marker
+ User::Leave( KErrCorrupt );
+ break;
+ }
+ }
+ // Check for underflow
+ if ( retCode != EFrameComplete )
+ {
+ // Request to jump to another section of the image file
+ if ( retCode == EFrameIncompleteRepositionRequest )
+ {
+ // Update the internal counter for data processed
+ iReader.UpdateTileHeader();
+ }
+
+ aSrc.Shift( iReader.iPtr - iReader.iPtrStart );
+ return retCode;
+ }
+
+ if ( iFHState != EStateInSkipTile && iFHState != EStateInSOT )
+ {
+ // Update the internal counter for data processed
+ // only for the current tile
+ iReader.UpdateTileHeader();
+ }
+
+ if ( ( iProgressBar && iFHState != EStateInEOC ) || iDecodeTile )
+ {
+ iProgressBar = EFalse;
+ aSrc.Shift( iReader.iPtr - iReader.iPtrStart );
+ return EFrameIncomplete;
+ }
+ }
+
+ if ( iDecodeTile == EFalse )
+ {
+ ImageProcessor()->FlushPixels();
+ }
+
+ return EFrameComplete;
+ }
+
+// -----------------------------------------------------------------------------
+// CJp2kReadCodec::GetNewDataPosition
+// Get the new offset where data should be read from.
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+void CJp2kReadCodec::GetNewDataPosition( TInt& aPosition, TInt& /*aLength*/ )
+ {
+ // Set new offset position so that
+ // ICL framework will read in more image data for processing
+ aPosition = iReader.iNewDataStart + iJ2kInfo.iCSOffset;
+ }
+
+// -----------------------------------------------------------------------------
+// CJp2kReadCodec::CJp2kReadCodec
+// C++ default constructor can NOT contain any code, that
+// might leave.
+// -----------------------------------------------------------------------------
+//
+CJp2kReadCodec::CJp2kReadCodec( const TJ2kInfo& aJ2kInfo ) :
+ iJ2kInfo( aJ2kInfo )
+ {
+ }
+
+// -----------------------------------------------------------------------------
+// CJp2kReadCodec::ConstructL
+// Symbian 2nd phase constructor can leave.
+// -----------------------------------------------------------------------------
+//
+void CJp2kReadCodec::ConstructL()
+ {
+ iImageInfo = new ( ELeave ) CJ2kImageInfo;
+
+ // Invoke base class 2nd phase constructor.
+ CImageProcessorReadCodec::ConstructL();
+ }
+
+// -----------------------------------------------------------------------------
+// CJp2kReadCodec::ReadSOCL
+// Verify and process Start of Codestream (SOC marker).
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+TFrameState CJp2kReadCodec::ReadSOCL()
+ {
+ const TUint8* dataPtr = iReader.iPtr;
+
+ if ( iJ2kInfo.iOption & TJ2kInfo::EJP2file )
+ {
+ // Codestream box in JP2 file format
+ iReader.iCSLength = iJ2kInfo.iCSBoxLength;
+ iReader.iPtr += KJ2kBoxTypeLength;
+
+ if ( iReader.iCSLength == 1 )
+ {
+ // The XLBox shall exist and contains the actual length of the box
+ // XLBox is 8 bytes width
+ iReader.iCSLength = PtrReadUtil::ReadBigEndianUint32Inc( iReader.iPtr );
+ iReader.iCSLength += PtrReadUtil::ReadBigEndianUint32Inc( iReader.iPtr );
+
+ // Populate back to the iJ2kInfo
+ CONST_CAST( TJ2kInfo&, iJ2kInfo ).iCSBoxLength = iReader.iCSLength;
+ }
+ }
+
+ if ( ( iReader.iPtrEnd - iReader.iPtr ) < KMarkerSize )
+ {
+ // Underflow, backup the pointer to the beginning
+ iReader.iPtr = dataPtr;
+ return EFrameIncomplete;
+ }
+
+ if ( PtrReadUtil::ReadBigEndianUint16Inc( iReader.iPtr ) != KSOC )
+ {
+ // Unrecognized SOC marker
+ User::Leave( KErrCorrupt );
+ }
+
+ // SIZ marker shall immediately follow the SOC marker
+ iFHState = EStateInSIZ;
+
+ return EFrameComplete;
+ }
+
+// -----------------------------------------------------------------------------
+// CJp2kReadCodec::ReadSIZL
+// Verify and process Image and Tile Size (SIZ marker).
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+TFrameState CJp2kReadCodec::ReadSIZL()
+ {
+ if ( ( iReader.iPtrEnd - iReader.iPtr ) < KMarkerMinLength )
+ {
+ // Underflow
+ return EFrameIncomplete;
+ }
+
+ if ( PtrReadUtil::ReadBigEndianUint16Inc( iReader.iPtr ) != KSIZ )
+ {
+ // Unrecognized SIZ marker
+ User::Leave( KErrCorrupt );
+ }
+
+ TUint16 markerLength = PtrReadUtil::ReadBigEndianUint16Inc( iReader.iPtr );
+
+ if ( ( iReader.iPtrEnd - iReader.iPtr ) < ( markerLength - KMarkerLength ) )
+ {
+ // Underflow, backup the iterator to the beginning of the marker
+ iReader.iPtr -= KMarkerMinLength;
+ return EFrameIncomplete;
+ }
+
+ TSizMarker& sizMarker = CONST_CAST( TSizMarker&, iImageInfo->SizMarker() );
+
+ sizMarker.iRsiz = PtrReadUtil::ReadBigEndianUint16Inc( iReader.iPtr );
+ sizMarker.iXsiz = PtrReadUtil::ReadBigEndianUint32Inc( iReader.iPtr );
+ sizMarker.iYsiz = PtrReadUtil::ReadBigEndianUint32Inc( iReader.iPtr );
+ sizMarker.iXOsiz = PtrReadUtil::ReadBigEndianUint32Inc( iReader.iPtr );
+ sizMarker.iYOsiz = PtrReadUtil::ReadBigEndianUint32Inc( iReader.iPtr );
+ sizMarker.iXTsiz = PtrReadUtil::ReadBigEndianUint32Inc( iReader.iPtr );
+ sizMarker.iYTsiz = PtrReadUtil::ReadBigEndianUint32Inc( iReader.iPtr );
+ sizMarker.iXTOsiz = PtrReadUtil::ReadBigEndianUint32Inc( iReader.iPtr );
+ sizMarker.iYTOsiz = PtrReadUtil::ReadBigEndianUint32Inc( iReader.iPtr );
+ sizMarker.iCsiz = PtrReadUtil::ReadBigEndianUint16Inc( iReader.iPtr );
+
+ if(sizMarker.iXOsiz > sizMarker.iXsiz || sizMarker.iYOsiz > sizMarker.iYsiz)
+ {
+ // Image offset is larger than image size, exit
+ User::Leave( KErrCorrupt );
+ }
+
+ if(sizMarker.iXTOsiz > sizMarker.iXsiz || sizMarker.iYTOsiz > sizMarker.iYsiz)
+ {
+ // Tile offset is larger than image size, exit
+ User::Leave( KErrCorrupt );
+ }
+
+ for ( TUint16 index = 0; index < sizMarker.iCsiz; ++index )
+ {
+ // Component's information
+ User::LeaveIfError( sizMarker.iSsiz.Append( *iReader.iPtr++ ) );
+ User::LeaveIfError( sizMarker.iXRsiz.Append( *iReader.iPtr++ ) );
+ User::LeaveIfError( sizMarker.iYRsiz.Append( *iReader.iPtr++ ) );
+
+ if((( sizMarker.iSsiz[index] & 0x7f ) + 1) > KMaxBitdepth )
+ {
+ // Invalid bitdepth for this component, exit
+ User::Leave( KErrCorrupt );
+ }
+ }
+
+ if ( iJ2kInfo.iCMPList.Count() > sizMarker.iCsiz )
+ {
+ // Populate the remaining component Rsiz using component 0's Rsiz
+ TUint16 indexi = (TUint16)( iJ2kInfo.iCMPList.Count() - sizMarker.iCsiz );
+ while ( indexi )
+ {
+ User::LeaveIfError( sizMarker.iXRsiz.Append( sizMarker.iXRsiz[0] ) );
+ User::LeaveIfError( sizMarker.iYRsiz.Append( sizMarker.iYRsiz[0] ) );
+ --indexi;
+ }
+ }
+
+ // Make sure we read all the data
+ if ( ( iReader.iPtr - iReader.iPtrStartMarker ) != ( markerLength + KMarkerSize ) )
+ {
+ // We must be missing some data in the marker
+ User::Leave( KErrCorrupt );
+ }
+
+ // Any valid marker may come after SIZ marker
+ iFHState = EStateInUnknown;
+
+ return EFrameComplete;
+ }
+
+// -----------------------------------------------------------------------------
+// CJp2kReadCodec::ReadCODL
+// Verify and process Coding Style Default (COD marker).
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+TFrameState CJp2kReadCodec::ReadCODL( TBool aMain )
+ {
+ if ( ( iReader.iPtrEnd - iReader.iPtr ) < KMarkerMinLength )
+ {
+ // Underflow
+ return EFrameIncomplete;
+ }
+
+ if ( PtrReadUtil::ReadBigEndianUint16Inc( iReader.iPtr ) != KCOD )
+ {
+ // Unrecognized COD marker
+ User::Leave(KErrCorrupt);
+ }
+
+ TUint16 markerLength = PtrReadUtil::ReadBigEndianUint16Inc( iReader.iPtr );
+
+ if ( ( iReader.iPtrEnd - iReader.iPtr ) < ( markerLength - KMarkerLength ) )
+ {
+ // Underflow, backup the iterator to the beginning of the marker
+ iReader.iPtr -= KMarkerMinLength;
+ return EFrameIncomplete;
+ }
+
+ TCODMarker *codMarker = NULL;
+
+ if ( aMain )
+ {
+ TMainMarker& mainMarker = CONST_CAST( TMainMarker&, iImageInfo->MainMarker() );
+ codMarker = &mainMarker.iCod;
+ }
+ else
+ {
+ // COD in Tile Part Header
+ codMarker = new ( ELeave ) TCODMarker;
+ CleanupDeletePushL( codMarker );
+ }
+
+ codMarker->iScod = *iReader.iPtr++;
+ codMarker->iProgressionOrder = *iReader.iPtr++;
+ codMarker->iNumOfLayers = PtrReadUtil::ReadBigEndianUint16Inc( iReader.iPtr );
+ codMarker->iColorTransformation = *iReader.iPtr++;
+ codMarker->iNumOfLevels = *iReader.iPtr++;
+
+ TUint8 tmp = (TUint8)( ( *iReader.iPtr++ ) + 2 );
+ codMarker->iCodeBlockSiz.iWidth = 1 << tmp;
+
+ tmp = (TUint8)( ( *iReader.iPtr++ ) + 2 );
+ codMarker->iCodeBlockSiz.iHeight = 1 << tmp;
+
+ codMarker->iCodeBlockStyle = *iReader.iPtr++;
+ codMarker->iWaveletTransformation = *iReader.iPtr++;
+
+ if ( codMarker->iScod & 0x01 )
+ {
+ // Entropy coder with precincts defined below
+ codMarker->iPrecinctSiz = HBufC8::NewL( codMarker->iNumOfLevels + 1 );
+ for ( TUint8 index = 0; index < codMarker->iNumOfLevels + 1; ++index )
+ {
+ codMarker->iPrecinctSiz->Des().Append( *iReader.iPtr++ );
+ }
+ }
+
+ // Make sure we read all the data
+ if ( ( iReader.iPtr - iReader.iPtrStartMarker ) != ( markerLength + KMarkerSize ) )
+ {
+ // We must be missing some data in the marker
+ User::Leave( KErrCorrupt );
+ }
+
+ if ( !aMain )
+ {
+ CJ2kTileInfo& tile = CONST_CAST( CJ2kTileInfo&, iImageInfo->TileAt( iLastTileIndex ) );
+
+ // Append COD to the current tile and decrement the tile length
+ tile.AppendCOD( codMarker, markerLength + KMarkerSize );
+ CleanupStack::Pop();
+ }
+
+ // Any valid marker may come after COD marker
+ iFHState = EStateInUnknown;
+ return EFrameComplete;
+ }
+
+// -----------------------------------------------------------------------------
+// CJp2kReadCodec::ReadCOCL
+// Verify and process Coding Style Component (COC marker).
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+TFrameState CJp2kReadCodec::ReadCOCL( TBool aMain )
+ {
+ if ( ( iReader.iPtrEnd - iReader.iPtr ) < KMarkerMinLength )
+ {
+ // Underflow
+ return EFrameIncomplete;
+ }
+
+ if ( PtrReadUtil::ReadBigEndianUint16Inc( iReader.iPtr ) != KCOC )
+ {
+ // Unrecognized COC marker
+ User::Leave( KErrCorrupt );
+ }
+
+ TUint16 markerLength = PtrReadUtil::ReadBigEndianUint16Inc( iReader.iPtr );
+
+ if ( ( iReader.iPtrEnd - iReader.iPtr ) < ( markerLength - KMarkerLength ) )
+ {
+ // Underflow, backup the iterator to the beginning of the marker
+ iReader.iPtr -= KMarkerMinLength;
+ return EFrameIncomplete;
+ }
+
+ const TSizMarker& sizMarker = iImageInfo->SizMarker();
+
+ TCOCMarker *cocMarker = new ( ELeave ) TCOCMarker;
+ CleanupDeletePushL(cocMarker);
+
+ if ( sizMarker.iCsiz < 257 )
+ {
+ // 8 bits component
+ cocMarker->iCcoc = *iReader.iPtr++;
+ }
+ else
+ {
+ // 16 bits component
+ cocMarker->iCcoc = PtrReadUtil::ReadBigEndianUint16Inc( iReader.iPtr );
+ }
+
+ cocMarker->iScoc = *iReader.iPtr++;
+ cocMarker->iNumOfLevels = *iReader.iPtr++;
+
+ TUint8 tmp = (TUint8)( ( *iReader.iPtr++ ) + 2 );
+ cocMarker->iCodeBlockSiz.iWidth = 1 << tmp;
+
+ tmp = (TUint8)( ( *iReader.iPtr++ ) + 2 );
+ cocMarker->iCodeBlockSiz.iHeight = 1 << tmp;
+
+ cocMarker->iCodeBlockStyle = *iReader.iPtr++;
+ cocMarker->iWaveletTransformation = *iReader.iPtr++;
+
+ if ( cocMarker->iScoc & 0x01 )
+ {
+ // Entropy coder with precincts defined below
+ cocMarker->iPrecinctSiz = HBufC8::NewL( cocMarker->iNumOfLevels + 1 );
+ for ( TUint8 index = 0; index < cocMarker->iNumOfLevels + 1; ++index )
+ {
+ cocMarker->iPrecinctSiz->Des().Append( *iReader.iPtr++ );
+ }
+ }
+
+ // Make sure we read all the data
+ if ( ( iReader.iPtr - iReader.iPtrStartMarker ) != ( markerLength + KMarkerSize ) )
+ {
+ // We must be missing some data in the marker
+ User::Leave( KErrCorrupt );
+ }
+
+ if ( aMain )
+ {
+ iImageInfo->AppendCOCL( cocMarker );
+ }
+ else
+ {
+ CJ2kTileInfo& tile = CONST_CAST( CJ2kTileInfo&, iImageInfo->TileAt( iLastTileIndex ) );
+
+ // Append COC to the current tile and decrement the tile length
+ tile.AppendCOCL( cocMarker, markerLength + KMarkerSize );
+ }
+ CleanupStack::Pop();
+
+ // Any valid marker may come after COC marker
+ iFHState = EStateInUnknown;
+
+ return EFrameComplete;
+ }
+
+// -----------------------------------------------------------------------------
+// CJp2kReadCodec::ReadQCDL
+// Verify and process Quantization Default (QCD marker).
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+TFrameState CJp2kReadCodec::ReadQCDL( TBool aMain )
+ {
+ if ( ( iReader.iPtrEnd - iReader.iPtr ) < KMarkerMinLength )
+ {
+ // Underflow
+ return EFrameIncomplete;
+ }
+
+ if ( PtrReadUtil::ReadBigEndianUint16Inc( iReader.iPtr ) != KQCD )
+ {
+ // Unrecognized QCD marker
+ User::Leave( KErrCorrupt );
+ }
+
+ TUint16 markerLength = PtrReadUtil::ReadBigEndianUint16Inc( iReader.iPtr );
+ if ( ( iReader.iPtrEnd - iReader.iPtr ) < ( markerLength - KMarkerLength ) )
+ {
+ // Underflow, backup the iterator to the beginning of the marker
+ iReader.iPtr -= KMarkerMinLength;
+ return EFrameIncomplete;
+ }
+
+ TQCDMarker *qcdMarker = NULL;
+
+ if ( aMain )
+ {
+ TMainMarker& mainMarker = CONST_CAST( TMainMarker&, iImageInfo->MainMarker() );
+ qcdMarker = &mainMarker.iQcd;
+ }
+ else
+ {
+ // QCD in Tile Part Header
+ qcdMarker = new ( ELeave ) TQCDMarker;
+
+ CleanupDeletePushL( qcdMarker );
+ }
+
+ qcdMarker->iSqcd = *iReader.iPtr++;
+
+ if ( qcdMarker->iSqcd & 0x01 )
+ {
+ // Scalar derived (values signalled for NLL subband only)
+ TUint16 tmp = PtrReadUtil::ReadBigEndianUint16Inc( iReader.iPtr );
+ qcdMarker->iExponent = HBufC8::NewL(1);
+ qcdMarker->iExponent->Des().Append( (TUint8)( (tmp >> 11) & 0x1f ) );
+ qcdMarker->iMantissa = HBufC16::NewL(1);
+ qcdMarker->iMantissa->Des().Append( (TUint16)( tmp & 0x07ff ) );
+ }
+ else
+ {
+ TInt entries = markerLength - ( iReader.iPtr - iReader.iPtrStartMarker ) + KMarkerSize;
+ if ( qcdMarker->iSqcd & 0x1f )
+ {
+ // Word oriented
+ TUint16 tmp;
+ qcdMarker->iExponent = HBufC8::NewL( entries / 2 );
+ qcdMarker->iMantissa = HBufC16::NewL( entries / 2 );
+
+ while ( entries >= 2 )
+ {
+ tmp = PtrReadUtil::ReadBigEndianUint16Inc( iReader.iPtr );
+ qcdMarker->iExponent->Des().Append((TUint8)( ( tmp >> 11) & 0x1f ) );
+ qcdMarker->iMantissa->Des().Append((TUint16)( tmp & 0x07ff ) );
+ entries -= 2;
+ }
+ }
+ else
+ {
+ // No quantization
+ qcdMarker->iExponent = HBufC8::NewL( entries );
+ while ( entries )
+ {
+ qcdMarker->iExponent->Des().Append( (TUint8)( ( *iReader.iPtr++ >> 3 ) & 0x1f ) );
+ --entries;
+ }
+ }
+ }
+
+ // Make sure we read all the data
+ if ( ( iReader.iPtr - iReader.iPtrStartMarker ) != ( markerLength + KMarkerSize ) )
+ {
+ // We must be missing some data in the marker
+ User::Leave( KErrCorrupt );
+ }
+
+ if ( !aMain )
+ {
+ CJ2kTileInfo& tile = CONST_CAST( CJ2kTileInfo&, iImageInfo->TileAt( iLastTileIndex ) );
+
+ // Append QCD to the current tile and decrement the tile length
+ tile.AppendQCD( qcdMarker, markerLength + KMarkerSize );
+ CleanupStack::Pop();
+ }
+
+ // Any valid marker may come after QCD marker
+ iFHState = EStateInUnknown;
+
+ return EFrameComplete;
+ }
+
+// -----------------------------------------------------------------------------
+// CJp2kReadCodec::ReadQCCL
+// Verify and process Quantization Component (QCC marker).
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+TFrameState CJp2kReadCodec::ReadQCCL(TBool aMain)
+ {
+ if ( ( iReader.iPtrEnd - iReader.iPtr ) < KMarkerMinLength )
+ {
+ // Underflow
+ return EFrameIncomplete;
+ }
+
+ if ( PtrReadUtil::ReadBigEndianUint16Inc( iReader.iPtr ) != KQCC )
+ {
+ // Unrecognized QCC marker
+ User::Leave( KErrCorrupt );
+ }
+
+ TUint16 markerLength = PtrReadUtil::ReadBigEndianUint16Inc( iReader.iPtr );
+ if ( ( iReader.iPtrEnd - iReader.iPtr ) < (markerLength - KMarkerLength ) )
+ {
+ // Underflow, backup the iterator to the beginning of the marker
+ iReader.iPtr -= KMarkerMinLength;
+ return EFrameIncomplete;
+ }
+
+ const TSizMarker& sizMarker = iImageInfo->SizMarker();
+
+ TQCCMarker *qccMarker = new (ELeave) TQCCMarker;
+
+ CleanupDeletePushL( qccMarker );
+
+ if ( sizMarker.iCsiz < 257 )
+ {
+ // 8 bits component
+ qccMarker->iCqcc = *iReader.iPtr++;
+ }
+ else
+ {
+ // 16 bit component
+ qccMarker->iCqcc = PtrReadUtil::ReadBigEndianUint16Inc( iReader.iPtr );
+ }
+
+ qccMarker->iSqcc = *iReader.iPtr++;
+
+ if ( qccMarker->iSqcc & 0x01 )
+ {
+ // Scalar derived (values signalled for NLL subband only)
+ TUint16 tmp = PtrReadUtil::ReadBigEndianUint16Inc( iReader.iPtr );
+ qccMarker->iExponent = HBufC8::NewL(1);
+ qccMarker->iExponent->Des().Append( (TUint8)( ( tmp >> 11 ) & 0x1f ) );
+ qccMarker->iMantissa = HBufC16::NewL(1);
+ qccMarker->iMantissa->Des().Append( (TUint16)( tmp & 0x07ff ) );
+ }
+ else
+ {
+ TInt entries = markerLength - ( iReader.iPtr - iReader.iPtrStartMarker ) + KMarkerSize;
+ if ( qccMarker->iSqcc & 0x1f )
+ {
+ // Word oriented
+ TUint16 tmp;
+ qccMarker->iExponent = HBufC8::NewL( entries / 2 );
+ qccMarker->iMantissa = HBufC16::NewL( entries / 2 );
+
+ while ( entries >= 2 )
+ {
+ tmp = PtrReadUtil::ReadBigEndianUint16Inc( iReader.iPtr );
+ qccMarker->iExponent->Des().Append( (TUint8)( ( tmp >> 11 ) & 0x1f ) );
+ qccMarker->iMantissa->Des().Append( (TUint16)( tmp & 0x07ff ) );
+ entries -= 2;
+ }
+ }
+ else
+ {
+ // No quantization
+ qccMarker->iExponent = HBufC8::NewL( entries );
+ while ( entries )
+ {
+ qccMarker->iExponent->Des().Append( (TUint8)( ( *iReader.iPtr++ >> 3 ) & 0x1f ) );
+ --entries;
+ }
+ }
+ }
+
+ // Make sure we read all the data
+ if ( ( iReader.iPtr - iReader.iPtrStartMarker ) != ( markerLength + KMarkerSize ) )
+ {
+ // We must be missing some data in the marker
+ User::Leave( KErrCorrupt );
+ }
+
+ if ( aMain )
+ {
+ iImageInfo->AppendQCCL( qccMarker );
+ }
+ else
+ {
+ CJ2kTileInfo& tile = CONST_CAST( CJ2kTileInfo&, iImageInfo->TileAt( iLastTileIndex ) );
+
+ // Append QCC to the current tile and decrement the tile length
+ tile.AppendQCCL( qccMarker, markerLength + KMarkerSize );
+ }
+ CleanupStack::Pop();
+
+ // Any valid marker may come after QCC marker
+ iFHState = EStateInUnknown;
+
+ return EFrameComplete;
+ }
+
+// -----------------------------------------------------------------------------
+// CJp2kReadCodec::ReadRGNL
+// Verify and process Region of Interest (RGN marker).
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+TFrameState CJp2kReadCodec::ReadRGNL( TBool aMain )
+ {
+ if ( ( iReader.iPtrEnd - iReader.iPtr ) < KMarkerMinLength )
+ {
+ // Underflow
+ return EFrameIncomplete;
+ }
+
+ if ( PtrReadUtil::ReadBigEndianUint16Inc( iReader.iPtr ) != KRGN )
+ {
+ // Unrecognized RGN marker
+ User::Leave( KErrCorrupt );
+ }
+
+ TUint16 markerLength = PtrReadUtil::ReadBigEndianUint16Inc( iReader.iPtr );
+
+ if ( ( iReader.iPtrEnd - iReader.iPtr ) < ( markerLength - KMarkerLength ) )
+ {
+ // Underflow, backup the iterator to the beginning of the marker
+ iReader.iPtr -= KMarkerMinLength;
+ return EFrameIncomplete;
+ }
+
+ const TSizMarker& sizMarker = iImageInfo->SizMarker();
+
+ TRGNMarker *rgnMarker = new ( ELeave ) TRGNMarker;
+ CleanupDeletePushL( rgnMarker );
+
+ if ( sizMarker.iCsiz < 257 )
+ {
+ // 8 bits component
+ rgnMarker->iCrgn = *iReader.iPtr++;
+ }
+ else
+ {
+ // 16 bits component
+ rgnMarker->iCrgn = PtrReadUtil::ReadBigEndianUint16Inc( iReader.iPtr );
+ }
+
+ rgnMarker->iSrgn = *iReader.iPtr++;
+ rgnMarker->iSPrgn = *iReader.iPtr++;
+
+ // Make sure we read all the data
+ if ( ( iReader.iPtr - iReader.iPtrStartMarker ) != ( markerLength + KMarkerSize ) )
+ {
+ // We must be missing some data in the marker
+ User::Leave( KErrCorrupt );
+ }
+
+ if ( aMain )
+ {
+ iImageInfo->AppendRGNL( rgnMarker );
+ }
+ else
+ {
+ CJ2kTileInfo& tile = CONST_CAST( CJ2kTileInfo&, iImageInfo->TileAt( iLastTileIndex ) );
+
+ // Append RGN to the current tile and decrement the tile length
+ tile.AppendRGNL( rgnMarker, markerLength + KMarkerSize );
+ }
+ CleanupStack::Pop();
+
+ // Any valid marker may come after RGN marker
+ iFHState = EStateInUnknown;
+
+ return EFrameComplete;
+ }
+
+// -----------------------------------------------------------------------------
+// CJp2kReadCodec::ReadPOCL
+// Verify and process Progression Order Change ( POC marker ).
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+TFrameState CJp2kReadCodec::ReadPOCL( TBool aMain )
+ {
+ if ( ( iReader.iPtrEnd - iReader.iPtr ) < KMarkerMinLength )
+ {
+ // Underflow
+ return EFrameIncomplete;
+ }
+
+ if ( PtrReadUtil::ReadBigEndianUint16Inc( iReader.iPtr ) != KPOC )
+ {
+ // Unrecognized COC marker
+ User::Leave( KErrCorrupt );
+ }
+
+ TUint16 markerLength = PtrReadUtil::ReadBigEndianUint16Inc( iReader.iPtr );
+ if ( ( iReader.iPtrEnd - iReader.iPtr ) < ( markerLength - KMarkerLength ) )
+ {
+ // Underflow, backup the iterator to the beginning of the marker
+ iReader.iPtr -= KMarkerMinLength;
+ return EFrameIncomplete;
+ }
+
+ const TSizMarker& sizMarker = iImageInfo->SizMarker();
+
+ TPOCMarker *pocMarker = new ( ELeave ) TPOCMarker;
+ CleanupDeletePushL( pocMarker );
+
+ TInt entries = markerLength - KMarkerSize;
+ TInt sizEntry = ( sizMarker.iCsiz < 257 ) ? 7 : 9;
+
+ while ( entries >= sizEntry )
+ {
+ User::LeaveIfError( pocMarker->iRSpoc.Append( *iReader.iPtr++ ) );
+
+ if ( sizMarker.iCsiz < 257 )
+ {
+ // 8 bits component
+ User::LeaveIfError( pocMarker->iCSpoc.Append( *iReader.iPtr++ ) );
+ }
+ else
+ {
+ // 16 bits component
+ User::LeaveIfError( pocMarker->iCSpoc.Append( PtrReadUtil::ReadBigEndianUint16Inc( iReader.iPtr ) ) );
+ }
+ User::LeaveIfError( pocMarker->iLYEpoc.Append( PtrReadUtil::ReadBigEndianUint16Inc( iReader.iPtr ) ) );
+ User::LeaveIfError( pocMarker->iREpoc.Append( *iReader.iPtr++ ) );
+ if ( sizMarker.iCsiz < 257 )
+ {
+ // 8 bits component
+ User::LeaveIfError( pocMarker->iCEpoc.Append( *iReader.iPtr++ ) );
+ }
+ else
+ {
+ // 16 bits component
+ User::LeaveIfError( pocMarker->iCEpoc.Append( PtrReadUtil::ReadBigEndianUint16Inc( iReader.iPtr ) ) );
+ }
+ User::LeaveIfError( pocMarker->iPpoc.Append( *iReader.iPtr++ ) );
+
+ entries -= sizEntry;
+ }
+
+ // Make sure we read all the data
+ if ( ( iReader.iPtr - iReader.iPtrStartMarker ) != ( markerLength + KMarkerSize ) )
+ {
+ // We must be missing some data in the marker
+ User::Leave( KErrCorrupt );
+ }
+
+ if ( aMain )
+ {
+ iImageInfo->AppendPOCL( pocMarker );
+ }
+ else
+ {
+ CJ2kTileInfo& tile = CONST_CAST( CJ2kTileInfo&, iImageInfo->TileAt( iLastTileIndex ) );
+
+ // Append POC to the current tile and decrement the tile length
+ tile.AppendPOCL( pocMarker, markerLength + KMarkerSize );
+ }
+ CleanupStack::Pop( );
+
+ // Any valid marker may come after POC marker
+ iFHState = EStateInUnknown;
+
+ return EFrameComplete;
+ }
+
+// -----------------------------------------------------------------------------
+// CJp2kReadCodec::ReadPPML
+// Verify and process Packed Packet Headers, Main Header ( PPM marker ).
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+TFrameState CJp2kReadCodec::ReadPPML()
+ {
+ TUint8 isUnderflow = EFalse;
+ if ( !iPreviousPPM )
+ {
+ if ( ( iReader.iPtrEnd - iReader.iPtr ) < KMarkerMinLength )
+ {
+ // Underflow
+ return EFrameIncomplete;
+ }
+
+ if ( PtrReadUtil::ReadBigEndianUint16Inc( iReader.iPtr ) != KPPM )
+ {
+ // Unrecognized PPM marker
+ User::Leave( KErrCorrupt );
+ }
+
+ TUint16 markerLength = PtrReadUtil::ReadBigEndianUint16Inc( iReader.iPtr );
+ if ( ( iReader.iPtrEnd - iReader.iPtr ) < ( KMarkerLength + 1 ) )
+ {
+ // Underflow, we need Zppm and Nppm to be in the buffer
+ // backup the iterator to the beginning of the marker
+ iReader.iPtr -= KMarkerMinLength;
+ return EFrameIncomplete;
+ }
+
+ if ( ( iReader.iPtrEnd - iReader.iPtr ) < ( markerLength - KMarkerLength ) )
+ {
+ // Underflow, will keep reading
+ isUnderflow = ETrue;
+ }
+
+ TPPMMarker *ppmMarker = new ( ELeave ) TPPMMarker;
+ CleanupDeletePushL( ppmMarker );
+
+ ppmMarker->iZppm = *iReader.iPtr++;
+ TUint32 entries = (TUint32)( markerLength - KMarkerSize - 1 );
+
+ ppmMarker->iNppm = entries;
+ ppmMarker->iIppm = HBufC8::NewL( entries );
+
+ if ( !isUnderflow )
+ {
+ ppmMarker->iIppm->Des( ).Append( iReader.iPtr, entries );
+ iReader.iPtr += entries;
+ iPreviousPPM = 0;
+
+ // Make sure we read all the data
+ if ( ( iReader.iPtr - iReader.iPtrStartMarker ) != ( markerLength + KMarkerSize ) )
+ {
+ // We must be missing some data in the marker
+ User::Leave( KErrCorrupt );
+ }
+ }
+ else
+ {
+ ppmMarker->iIppm->Des().Append( iReader.iPtr, ( iReader.iPtrEnd - iReader.iPtr ) );
+ ppmMarker->iRemainder = (TUint32)( entries - ( iReader.iPtrEnd - iReader.iPtr ) );
+ iReader.iPtr = iReader.iPtrEnd;
+ iPreviousPPM = ppmMarker;
+ }
+
+ // Insert the new PPM marker into the right order
+ TMainMarker& mainMarker = CONST_CAST( TMainMarker&, iImageInfo->MainMarker() );
+ TUint8 tmp = ETrue;
+ if ( mainMarker.iPpm.Count() > 0 &&
+ mainMarker.iPpm[mainMarker.iPpm.Count() - 1]->iZppm > ppmMarker->iZppm )
+ {
+ for ( entries = 0; entries < (TUint32)mainMarker.iPpm.Count(); ++entries )
+ {
+ // Order by iZppm of the PPM marker
+ if ( mainMarker.iPpm[entries]->iZppm > ppmMarker->iZppm )
+ {
+ User::LeaveIfError( mainMarker.iPpm.Insert( ppmMarker, entries ) );
+
+ tmp = EFalse;
+ entries = (TUint32)mainMarker.iPpm.Count();
+ }
+ }
+ }
+
+ if ( tmp )
+ {
+ User::LeaveIfError( mainMarker.iPpm.Append( ppmMarker ) );
+ }
+ CleanupStack::Pop();
+ }
+ else
+ {
+ if ( (TUint32)( iReader.iPtrEnd - iReader.iPtr ) < iPreviousPPM->iRemainder )
+ {
+ // Continue reading incomplete COM marker
+ iPreviousPPM->iIppm->Des().Append( iReader.iPtr, ( iReader.iPtrEnd - iReader.iPtr ) );
+ iPreviousPPM->iRemainder = (TUint32)( iPreviousPPM->iRemainder - ( iReader.iPtrEnd - iReader.iPtr ) );
+ iReader.iPtr = iReader.iPtrEnd;
+ isUnderflow = ETrue;
+ }
+ else
+ {
+ // We have the complete COM marker now
+ iPreviousPPM->iIppm->Des().Append( iReader.iPtr, iPreviousPPM->iRemainder );
+ iReader.iPtr += iPreviousPPM->iRemainder;
+ iPreviousPPM->iRemainder = 0;
+ iPreviousPPM = 0;
+ }
+ }
+
+ if ( !isUnderflow )
+ {
+ // Any valid marker may come after PPM marker
+ iFHState = EStateInUnknown;
+ return EFrameComplete;
+ }
+ else
+ {
+ // Underflow, stay in the same state
+ iReader.UpdateMainHeader();
+ return EFrameIncomplete;
+ }
+ }
+
+// -----------------------------------------------------------------------------
+// CJp2kReadCodec::ReadTLML
+// Verify and process Tile Part Lengths, Main Header ( TLM marker ).
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+TFrameState CJp2kReadCodec::ReadTLML()
+ {
+ if ( ( iReader.iPtrEnd - iReader.iPtr ) < KMarkerMinLength )
+ {
+ // Underflow
+ return EFrameIncomplete;
+ }
+
+ if ( PtrReadUtil::ReadBigEndianUint16Inc( iReader.iPtr ) != KTLM )
+ {
+ // Unrecognized TLM marker
+ User::Leave( KErrCorrupt );
+ }
+
+ TUint16 markerLength = PtrReadUtil::ReadBigEndianUint16Inc( iReader.iPtr );
+ if ( ( iReader.iPtrEnd - iReader.iPtr ) < ( markerLength - KMarkerLength ) )
+ {
+ // Underflow, backup the iterator to the beginning of the marker
+ iReader.iPtr -= KMarkerMinLength;
+ return EFrameIncomplete;
+ }
+
+ TTLMMarker *tlmMarker = new ( ELeave ) TTLMMarker;
+ CleanupDeletePushL( tlmMarker );
+
+ tlmMarker->iZtlm = *iReader.iPtr++;
+ tlmMarker->iStlm = *iReader.iPtr++;
+
+ TInt entries = markerLength - ( 2 * KMarkerSize );
+ TUint8 st = (TUint8)( ( tlmMarker->iStlm >> 4 ) & 0x03 );
+ TUint8 sp = (TUint8)( ( tlmMarker->iStlm >> 6 ) & 0x01 );
+ TInt sizEntry = st;
+ sizEntry += ( sp ? 4 : 2 );
+
+ while ( entries >= sizEntry )
+ {
+ if ( st == 1 )
+ {
+ // 8 bits tile index
+ User::LeaveIfError( tlmMarker->iTtlm.Append( *iReader.iPtr++ ) );
+ }
+ else if ( st == 2 )
+ {
+ // 16 bits tile index
+ User::LeaveIfError( tlmMarker->iTtlm.Append( PtrReadUtil::ReadBigEndianUint16Inc( iReader.iPtr ) ) );
+ }
+ if ( sp ) //lint !e961 no else is needed here at the end of if...else if
+ {
+ // 32 bits length
+ User::LeaveIfError( tlmMarker->iPtlm.Append( PtrReadUtil::ReadBigEndianUint32Inc( iReader.iPtr ) ) );
+ }
+ else
+ {
+ // 16 bits length
+ User::LeaveIfError( tlmMarker->iPtlm.Append( PtrReadUtil::ReadBigEndianUint16Inc( iReader.iPtr ) ) );
+ }
+ entries -= sizEntry;
+ }
+
+ // Make sure we read all the data
+ if ( ( iReader.iPtr - iReader.iPtrStartMarker ) != ( markerLength + KMarkerSize ) )
+ {
+ // We must be missing some data in the marker
+ User::Leave( KErrCorrupt );
+ }
+
+ // Insert the new TLM marker into the right order
+ TMainMarker& mainMarker = CONST_CAST( TMainMarker&, iImageInfo->MainMarker() );
+ sp = 1;
+ for ( entries = 0; entries < mainMarker.iTlm.Count(); ++entries )
+ {
+ // Order by iZtlm of the TLM marker
+ if ( mainMarker.iTlm[entries]->iZtlm > tlmMarker->iZtlm )
+ {
+ User::LeaveIfError( mainMarker.iTlm.Insert( tlmMarker, entries ) );
+ sp = 0;
+ entries = mainMarker.iTlm.Count();
+ }
+ }
+
+ if ( sp )
+ {
+ User::LeaveIfError( mainMarker.iTlm.Append( tlmMarker ) );
+ }
+ CleanupStack::Pop();
+
+ // Any valid marker may come after TLM marker
+ iFHState = EStateInUnknown;
+
+ return EFrameComplete;
+ }
+
+// -----------------------------------------------------------------------------
+// CJp2kReadCodec::ReadPLML
+// Verify and process Packet Length, Main Header ( PLM marker ).
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+TFrameState CJp2kReadCodec::ReadPLML()
+ {
+ if ( ( iReader.iPtrEnd - iReader.iPtr ) < KMarkerMinLength )
+ {
+ // Underflow
+ return EFrameIncomplete;
+ }
+
+ if ( PtrReadUtil::ReadBigEndianUint16Inc( iReader.iPtr ) != KPLM )
+ {
+ // Unrecognized PLM marker
+ User::Leave( KErrCorrupt );
+ }
+
+ TUint16 markerLength = PtrReadUtil::ReadBigEndianUint16Inc( iReader.iPtr );
+ if ( ( iReader.iPtrEnd - iReader.iPtr ) < ( markerLength - KMarkerLength ) )
+ {
+ // Underflow, backup the iterator to the beginning of the marker
+ iReader.iPtr -= KMarkerMinLength;
+ return EFrameIncomplete;
+ }
+
+ TPLMMarker *plmMarker = new ( ELeave ) TPLMMarker;
+ CleanupDeletePushL( plmMarker );
+
+ plmMarker->iZplm = *iReader.iPtr++;
+ TUint32 entries = (TUint32)( markerLength - KMarkerSize - 1 );
+
+ plmMarker->iNplm = (TUint8)entries;
+ plmMarker->iIplm = HBufC8::NewL( entries );
+ plmMarker->iIplm->Des().Append( iReader.iPtr, entries );
+ iReader.iPtr += entries;
+
+ // Make sure we read all the data
+ if ( ( iReader.iPtr - iReader.iPtrStartMarker ) != ( markerLength + KMarkerSize ) )
+ {
+ // We must be missing some data in the marker
+ User::Leave( KErrCorrupt );
+ }
+
+ // Insert the new PLM marker into the right order
+ TMainMarker& mainMarker = CONST_CAST( TMainMarker&, iImageInfo->MainMarker() );
+ TUint8 tmp = ETrue;
+
+ if ( mainMarker.iPlm.Count() > 0 &&
+ mainMarker.iPlm[mainMarker.iPlm.Count() - 1]->iZplm > plmMarker->iZplm )
+ {
+ for ( entries = 0; entries < (TUint32)mainMarker.iPlm.Count(); ++entries )
+ {
+ // Order by iZplm of the PLM marker
+ if ( mainMarker.iPlm[entries]->iZplm > plmMarker->iZplm )
+ {
+ User::LeaveIfError( mainMarker.iPlm.Insert( plmMarker, entries ) );
+ tmp = EFalse;
+ entries = (TUint32)mainMarker.iPlm.Count();
+ }
+ }
+ }
+
+ if ( tmp )
+ {
+ User::LeaveIfError( mainMarker.iPlm.Append( plmMarker ) );
+ }
+ CleanupStack::Pop();
+
+ // Any valid marker may come after PLM marker
+ iFHState = EStateInUnknown;
+
+ return EFrameComplete;
+ }
+
+// -----------------------------------------------------------------------------
+// CJp2kReadCodec::ReadCRGL
+// Verify and process Component Registration, Main Header ( CRG marker ).
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+TFrameState CJp2kReadCodec::ReadCRGL()
+ {
+ if ( ( iReader.iPtrEnd - iReader.iPtr ) < KMarkerMinLength )
+ {
+ // Underflow
+ return EFrameIncomplete;
+ }
+
+ if ( PtrReadUtil::ReadBigEndianUint16Inc( iReader.iPtr ) != KCRG )
+ {
+ // Unrecognized CRG marker
+ User::Leave( KErrCorrupt );
+ }
+
+ TUint16 markerLength = PtrReadUtil::ReadBigEndianUint16Inc( iReader.iPtr );
+ if ( ( iReader.iPtrEnd - iReader.iPtr ) < ( markerLength - KMarkerLength ) )
+ {
+ // Underflow, backup the iterator to the beginning of the marker
+ iReader.iPtr -= KMarkerMinLength;
+ return EFrameIncomplete;
+ }
+
+ TCRGMarker *crgMarker = new ( ELeave ) TCRGMarker;
+ CleanupDeletePushL( crgMarker );
+
+ TInt entries = markerLength - KMarkerSize;
+ TUint16 xCrg;
+ TUint16 yCrg;
+ while ( entries )
+ {
+ xCrg = PtrReadUtil::ReadBigEndianUint16Inc( iReader.iPtr );
+ yCrg = PtrReadUtil::ReadBigEndianUint16Inc( iReader.iPtr );
+ User::LeaveIfError( crgMarker->iXYcrg.Append( TPoint( xCrg, yCrg ) ) );
+ entries -= 4;
+ }
+
+ // Make sure we read all the data
+ if ( ( iReader.iPtr - iReader.iPtrStartMarker ) != ( markerLength + KMarkerSize ) )
+ {
+ // We must be missing some data in the marker
+ User::Leave( KErrCorrupt );
+ }
+
+ iImageInfo->AppendCRGL( crgMarker );
+
+ CleanupStack::Pop( );
+
+ // Any valid marker may come after CRG marker
+ iFHState = EStateInUnknown;
+
+ return EFrameComplete;
+ }
+
+// -----------------------------------------------------------------------------
+// CJp2kReadCodec::ReadCOML
+// Verify and process Comment ( COM marker ).
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+TFrameState CJp2kReadCodec::ReadCOML( TBool aMain )
+ {
+ TUint8 isUnderflow = EFalse;
+ if ( !iPreviousCOM )
+ {
+ if ( ( iReader.iPtrEnd - iReader.iPtr ) < KMarkerMinLength )
+ {
+ // Underflow
+ return EFrameIncomplete;
+ }
+
+ if ( PtrReadUtil::ReadBigEndianUint16Inc( iReader.iPtr ) != KCME )
+ {
+ // Unrecognized COM marker
+ User::Leave( KErrCorrupt );
+ }
+
+ TUint16 markerLength = PtrReadUtil::ReadBigEndianUint16Inc( iReader.iPtr );
+ if ( ( iReader.iPtrEnd - iReader.iPtr ) < KMarkerLength )
+ {
+ // Underflow, we need Rcom to be in the buffer
+ // backup the iterator to the beginning of the marker
+ iReader.iPtr -= KMarkerMinLength;
+ return EFrameIncomplete;
+ }
+
+ if ( ( iReader.iPtrEnd - iReader.iPtr ) < ( markerLength - KMarkerLength ) )
+ {
+ // Underflow, will keep reading
+ isUnderflow = ETrue;
+ }
+
+ TCOMMarker* comMarker = new ( ELeave ) TCOMMarker;
+ CleanupDeletePushL( comMarker );
+
+ comMarker->iRcom = PtrReadUtil::ReadBigEndianUint16Inc( iReader.iPtr );
+ TInt entries = markerLength - ( 2 * KMarkerSize );
+
+ comMarker->iCcom = HBufC8::NewL( entries );
+ if ( !isUnderflow )
+ {
+ comMarker->iCcom->Des().Append( iReader.iPtr, entries );
+ iReader.iPtr += entries;
+ iPreviousCOM = 0;
+
+ // Make sure we read all the data
+ if ( ( iReader.iPtr - iReader.iPtrStartMarker ) != ( markerLength + KMarkerSize ) )
+ {
+ // We must be missing some data in the marker
+ User::Leave( KErrCorrupt );
+ }
+ }
+ else
+ {
+ comMarker->iCcom->Des().Append( iReader.iPtr, ( iReader.iPtrEnd - iReader.iPtr ) );
+ comMarker->iRemainder = (TUint16)( entries - ( iReader.iPtrEnd - iReader.iPtr ) );
+ iReader.iPtr = iReader.iPtrEnd;
+ iPreviousCOM = comMarker;
+ }
+
+ if ( aMain )
+ {
+ iImageInfo->AppendCOML( comMarker );
+ }
+ else
+ {
+ CJ2kTileInfo& tile = CONST_CAST( CJ2kTileInfo&, iImageInfo->TileAt( iLastTileIndex ) );
+
+ // Append COM to the current tile and decrement the tile length
+ tile.AppendCOML( comMarker, markerLength + KMarkerSize );
+ }
+ CleanupStack::Pop();
+ }
+ else
+ {
+ if ( ( iReader.iPtrEnd - iReader.iPtr ) < iPreviousCOM->iRemainder )
+ {
+ // Continue reading incomplete COM marker
+ iPreviousCOM->iCcom->Des().Append( iReader.iPtr, ( iReader.iPtrEnd - iReader.iPtr ) );
+ iPreviousCOM->iRemainder = (TUint16)( iPreviousCOM->iRemainder - ( iReader.iPtrEnd - iReader.iPtr ) );
+ iReader.iPtr = iReader.iPtrEnd;
+ isUnderflow = ETrue;
+ }
+ else
+ {
+ // We have the complete COM marker now
+ iPreviousCOM->iCcom->Des( ).Append( iReader.iPtr, iPreviousCOM->iRemainder );
+ iReader.iPtr += iPreviousCOM->iRemainder;
+ iPreviousCOM->iRemainder = 0;
+ iPreviousCOM = 0;
+ }
+ }
+
+ if ( !isUnderflow )
+ {
+ // Any valid marker may come after COM marker
+ iFHState = EStateInUnknown;
+ return EFrameComplete;
+ }
+ else
+ {
+ // Underflow, stay in the same state
+ if ( aMain )
+ {
+ iReader.UpdateMainHeader( );
+ }
+ return EFrameIncomplete;
+ }
+ }
+
+// -----------------------------------------------------------------------------
+// CJp2kReadCodec::ReadSOTL
+// Verify and process Start of Tile Part ( SOT marker ).
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+TFrameState CJp2kReadCodec::ReadSOTL()
+ {
+ if ( ( iReader.iPtrEnd - iReader.iPtr ) < KMarkerMinLength )
+ {
+ // Underflow
+ return EFrameIncomplete;
+ }
+
+ if ( PtrReadUtil::ReadBigEndianUint16Inc( iReader.iPtr ) != KSOT )
+ {
+ // Unrecognized SOT marker
+ User::Leave( KErrCorrupt );
+ }
+
+ TUint16 markerLength = PtrReadUtil::ReadBigEndianUint16Inc( iReader.iPtr );
+ if ( ( iReader.iPtrEnd - iReader.iPtr ) < ( markerLength - KMarkerLength ) )
+ {
+ // Underflow, backup the iterator to the beginning of the marker
+ iReader.iPtr -= KMarkerMinLength;
+ return EFrameIncomplete;
+ }
+
+ TSotMarker sotMarker;
+ sotMarker.iIsot = PtrReadUtil::ReadBigEndianUint16Inc( iReader.iPtr );
+ sotMarker.iPsot = PtrReadUtil::ReadBigEndianUint32Inc( iReader.iPtr );
+ sotMarker.iTPsot = *iReader.iPtr++;
+ sotMarker.iTNsot = *iReader.iPtr++;
+
+ if(sotMarker.iIsot >= ( iImageInfo->NumOfHorizTiles() * iImageInfo->NumOfVertTiles() ))
+ {
+ // Invalid tile index, exceeds the number of tiles, exit
+ User::Leave( KErrCorrupt );
+ }
+
+ if ( sotMarker.iPsot == 0 )
+ {
+ // Try to look for tile part length information
+ // from the TLM in the main header - if there is one
+ iImageInfo->GetFromTLM( sotMarker );
+ }
+
+ iImageInfo->IncrementLastTilePartProcessed();
+
+ if ( iUseNewTile )
+ {
+ if ( sotMarker.iIsot < iLastTileIndex )
+ {
+ // Skip all tiles with iIsot smaller than the iLastTileIndex
+ iReader.iSkipLength = sotMarker.iPsot - markerLength - KMarkerSize;
+ iUseNewTile = EFalse;
+ iFHState = EStateInSkipTile;
+ return EFrameComplete;
+ }
+
+ if(sotMarker.iTPsot >= sotMarker.iTNsot)
+ {
+ // Skip the tiles where tile part index is larger than
+ // the number of tile parts
+ iReader.iSkipLength = sotMarker.iPsot - markerLength - KMarkerSize;
+ iUseNewTile = EFalse;
+ iFHState = EStateInSkipTile;
+ return EFrameComplete;
+ }
+
+ // Start using this tile as the current tile
+ iLastTileIndex = sotMarker.iIsot;
+
+ // Save the next tile offset
+ iReader.iNewDataStart += sotMarker.iPsot;
+ iUseNextTile = iSequential = ETrue;
+ }
+ else
+ {
+ if ( sotMarker.iIsot != iLastTileIndex )
+ {
+ if ( iUseNextTile )
+ {
+ if ( sotMarker.iIsot > iLastTileIndex )
+ {
+ iUseNextTile = EFalse;
+ }
+ }
+ iSequential = EFalse;
+
+ // Skip all tiles that are not equal to current tile
+ iReader.iSkipLength = sotMarker.iPsot - markerLength - KMarkerSize;
+ iFHState = EStateInSkipTile;
+ return EFrameComplete;
+ }
+ else
+ {
+ // Tiles are in sequential order
+ if ( iUseNextTile && iSequential )
+ {
+ // Save the next tile offset
+ iReader.iNewDataStart += sotMarker.iPsot;
+ }
+ }
+ }
+
+ CJ2kTileInfo *tile = 0;
+ if ( iUseNewTile )
+ {
+ tile = CJ2kTileInfo::NewLC( *iImageInfo, iReader );
+ }
+ else
+ {
+ tile = CONST_CAST( CJ2kTileInfo*, &iImageInfo->TileAt( iLastTileIndex ) );
+ }
+
+ // Set the SOT marker
+ tile->SetSotMarker( sotMarker );
+
+ if ( sotMarker.iPsot )
+ {
+ // Decrement the tile length
+ tile->SetTileLength( sotMarker.iPsot - markerLength - KMarkerSize );
+ }
+
+ // Make sure we read all the data
+ if ( ( iReader.iPtr - iReader.iPtrStartMarker ) != ( markerLength + KMarkerSize ) )
+ {
+ // We must be missing some data in the marker
+ User::Leave( KErrCorrupt );
+ }
+
+ if ( iUseNewTile )
+ {
+ iImageInfo->Append( tile );
+ CleanupStack::Pop();
+ iUseNewTile = EFalse;
+ }
+
+ // Any valid marker may come after SOT marker
+ iFHState = EStateInUnknown;
+ return EFrameComplete;
+
+ }
+
+// -----------------------------------------------------------------------------
+// CJp2kReadCodec::ReadSODL
+// Verify and process Start of Data ( SOD marker ).
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+TFrameState CJp2kReadCodec::ReadSODL()
+ {
+ if ( PtrReadUtil::ReadBigEndianUint16Inc( iReader.iPtr ) != KSOD )
+ {
+ // Unrecognized SOD marker
+ User::Leave( KErrCorrupt );
+ }
+
+ CJ2kTileInfo& tile = CONST_CAST( CJ2kTileInfo&, iImageInfo->TileAt( iLastTileIndex ) );
+
+ TUint32& length = tile.TileLength();
+ if ( length )
+ {
+ // Decrement the tile length
+ length -= KMarkerSize;
+ }
+
+ // Initialize the tile only for tile part 0
+ if ( tile.IsFirstTilePart() )
+ {
+ tile.InitializeL();
+ iImageInfo->SetLastTilePartProcessed( tile.SotMarker().iIsot );
+ }
+
+ if ( tile.IsPPT() )
+ {
+ // Use packet header information from PPT
+ tile.UsePPTL();
+ }
+ else if ( iImageInfo->IsPPM() )
+ {
+ // Use packet header information from PPM
+ iImageInfo->UsePPM( tile );
+ }
+ else
+ {
+ tile.SetPacketHeaderReader( &iReader );
+ }
+
+ if ( ( iImageInfo->NumOfHorizTiles() == 1 ) &&
+ ( iImageInfo->NumOfVertTiles() == 1 ) )
+ {
+ // To force a return immediately from ProcessFrameL()
+ // on first entry to stimulate the occurrance of
+ // the progress bar
+ iProgressBar = ETrue;
+ }
+
+ // We know that bitstream will follow SOD marker
+ iFHState = EStateInBITSTREAM;
+
+ return EFrameComplete;
+ }
+
+// -----------------------------------------------------------------------------
+// CJp2kReadCodec::ReadBitStreamL
+// Verify and process BitStream Data.
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+TFrameState CJp2kReadCodec::ReadBitStreamL()
+ {
+ CJ2kTileInfo& tile = CONST_CAST( CJ2kTileInfo&, iImageInfo->TileAt( iLastTileIndex ) );
+ TUint32& length = tile.TileLength( );
+
+ if ( length )
+ {
+ if ( ( iReader.iPtrEnd - iReader.iPtr ) < ( TInt32 )length )
+ {
+ // Larger bitstream will not fit into the internal
+ // buffer size, so process a chunk at a time
+ // we have to add some kind of state information
+ // so that we know where to continue and process
+ if ( tile.IsSpeedup() )
+ {
+ // For RLCP/RPCL progression order
+ if ( tile.LastLevelProcessed() <= tile.NumOfLevelsPOC() )
+ {
+ tile.ReadBitStreamL();
+ }
+ else
+ {
+ // discard any data that beyond the required resolution level
+ if ( !tile.IsPPT() )
+ {
+ if ( iImageInfo->IsPPM() )
+ {
+ // discard current packet header in PPM marker
+ iImageInfo->ResetPPM();
+ }
+ }
+ iReader.iPtr = iReader.iPtrEnd;
+ }
+ }
+ else
+ {
+ tile.ReadBitStreamL();
+ }
+
+ length -= ( iReader.iPtr - iReader.iPtrStartMarker );
+ iReader.UpdateTileHeader();
+
+ // stay in the current state
+ return EFrameIncomplete;
+ }
+
+ // We are sure that all tile part data fit into the buffer
+ // so just go ahead and process it
+ if ( tile.IsSpeedup() )
+ {
+ // For RLCP/RPCL progression order
+ if ( tile.LastLevelProcessed() <= tile.NumOfLevelsPOC() )
+ {
+ tile.ReadBitStreamL( ETrue );
+ iReader.TryReAlignReader();
+ }
+ else
+ {
+ // discard any data that beyond the required resolution level
+ if ( !tile.IsPPT() )
+ {
+ if ( iImageInfo->IsPPM() )
+ {
+ // discard current packet header in PPM marker
+ iImageInfo->ResetPPM();
+ }
+ }
+ iReader.iPtr += length;
+ }
+ }
+ else
+ {
+ tile.ReadBitStreamL( ETrue );
+ iReader.TryReAlignReader();
+ }
+
+ length -= ( iReader.iPtr - iReader.iPtrStartMarker );
+
+ if ( tile.IsSpeedup() )
+ {
+ // discard any data that beyond the required resolution level
+ if ( !tile.IsPPT() )
+ {
+ if ( iImageInfo->IsPPM() )
+ {
+ // discard current packet header in PPM marker
+ iImageInfo->ResetPPM();
+ }
+ }
+ iReader.iPtr += length;
+ length = 0;
+ }
+
+ // Sanity check
+ if ( length != 0 )
+ {
+ User::Leave( KErrCorrupt );
+ }
+
+ if ( tile.IsLastTilePart() )
+ {
+ tile.DoReleaseUnusedMarkers();
+
+ // proceed to the decoding state
+ iDecodeTile = ETrue;
+
+ // Start with new tile
+ iUseNewTile = ETrue;
+ if ( !iUseNextTile )
+ {
+ iFHState = EStateInUnknown;
+ return EFrameIncompleteRepositionRequest;
+ }
+ else
+ {
+ if ( !iSequential )
+ {
+ // Must be End of Codestream EOC
+ iFHState = EStateInEOC;
+ iReader.iPtr += KMarkerSize;
+ return EFrameComplete;
+ }
+ }
+ }
+
+ // We do not know what is the next marker
+ // either next SOT or EOC
+ iFHState = EStateInUnknown;
+ }
+ else
+ {
+ if ( iReader.iPtrEnd == iReader.iPtr )
+ {
+ // Assume that we have done with the image
+ iFHState = EStateInEOC;
+ }
+ else
+ {
+ if ( ( iReader.iPtrEnd - iReader.iPtr ) >= 2 )
+ {
+ TUint16 marker = PtrReadUtil::ReadBigEndianUint16( iReader.iPtr );
+ if ( marker == KSOT )
+ {
+ // Next SOT marker is found
+ iFHState = EStateInSOT;
+ }
+ else if ( marker == EStateInEOC )
+ {
+ // End of Codestream is found
+ iFHState = EStateInEOC;
+ iReader.iPtr += KMarkerSize;
+ }
+ else
+ {
+ tile.ReadBitStreamL();
+ marker = PtrReadUtil::ReadBigEndianUint16( iReader.iPtr );
+
+ if ( marker == KSOT || marker == KEOC )
+ {
+ iFHState = EStateInUnknown;
+
+ if ( tile.IsLastTilePart() )
+ {
+ tile.DoReleaseUnusedMarkers();
+
+ // proceed to the decoding state
+ iDecodeTile = ETrue;
+
+ // Start with new tile
+ iUseNewTile = ETrue;
+ if ( !iUseNextTile )
+ {
+ return EFrameIncompleteRepositionRequest;
+ }
+ else
+ {
+ if ( !iSequential )
+ {
+ // Must be End of Codestream EOC
+ iFHState = EStateInEOC;
+ iReader.iPtr += KMarkerSize;
+ }
+ }
+ }
+ }
+ else
+ {
+ iReader.UpdateTileHeader();
+
+ // Stay in the current state
+ return EFrameIncomplete;
+ }
+ }
+ }
+ else
+ {
+ iReader.UpdateTileHeader();
+
+ // Stay in the current state
+ return EFrameIncomplete;
+ }
+ }
+ }
+
+ if ( ( iImageInfo->NumOfHorizTiles() == 1 ) &&
+ ( iImageInfo->NumOfVertTiles() == 1 ) )
+ {
+ // To force a return immediately from ProcessFrameL()
+ // on first entry to stimulate the occurrance of
+ // the progress bar
+ iProgressBar = ETrue;
+ }
+
+ return EFrameComplete;
+ }
+
+// -----------------------------------------------------------------------------
+// CJp2kReadCodec::ReadPPTL
+// Verify and process Packed Packet Headers, Tile Part Header ( PPT marker ).
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+TFrameState CJp2kReadCodec::ReadPPTL()
+ {
+ if ( ( iReader.iPtrEnd - iReader.iPtr ) < KMarkerMinLength )
+ {
+ // Underflow
+ return EFrameIncomplete;
+ }
+
+ if ( PtrReadUtil::ReadBigEndianUint16Inc( iReader.iPtr ) != KPPT )
+ {
+ // Unrecognized PPT marker
+ User::Leave( KErrCorrupt );
+ }
+
+ TUint16 markerLength = PtrReadUtil::ReadBigEndianUint16Inc( iReader.iPtr );
+
+ if ( ( iReader.iPtrEnd - iReader.iPtr ) < ( markerLength - KMarkerLength ) )
+ {
+ // Underflow, backup the iterator to the beginning of the marker
+ iReader.iPtr -= KMarkerMinLength;
+ return EFrameIncomplete;
+ }
+
+ TPPTMarker *pptMarker = new ( ELeave ) TPPTMarker;
+ CleanupDeletePushL( pptMarker );
+
+ TInt entries = markerLength - KMarkerSize - 1;
+ pptMarker->iZppt = *iReader.iPtr++;
+ pptMarker->iIppt = HBufC8::NewL( entries );
+ pptMarker->iIppt->Des( ).Append( iReader.iPtr, entries );
+ iReader.iPtr += entries;
+
+ // Make sure we read all the data
+ if ( ( iReader.iPtr - iReader.iPtrStartMarker ) != ( markerLength + KMarkerSize ) )
+ {
+ // We must be missing some data in the marker
+ User::Leave( KErrCorrupt );
+ }
+
+ CJ2kTileInfo& tile = CONST_CAST( CJ2kTileInfo&, iImageInfo->TileAt( iLastTileIndex ) );
+
+ // Append PPT to the current tile and decrement the tile length
+ tile.AppendPPTL( pptMarker, markerLength + KMarkerSize );
+ CleanupStack::Pop();
+
+ // Any valid marker may come after PPT marker
+ iFHState = EStateInUnknown;
+
+ return EFrameComplete;
+ }
+
+// -----------------------------------------------------------------------------
+// CJp2kReadCodec::ReadPLTL
+// Verify and process Packet Length, Tile Part Header ( PLT marker ).
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+TFrameState CJp2kReadCodec::ReadPLTL()
+ {
+ if ( ( iReader.iPtrEnd - iReader.iPtr ) < KMarkerMinLength )
+ {
+ // Underflow
+ return EFrameIncomplete;
+ }
+
+ if ( PtrReadUtil::ReadBigEndianUint16Inc( iReader.iPtr ) != KPLT )
+ {
+ // Unrecognized PLT marker
+ User::Leave( KErrCorrupt );
+ }
+
+ TUint16 markerLength = PtrReadUtil::ReadBigEndianUint16Inc( iReader.iPtr );
+
+ if ( ( iReader.iPtrEnd - iReader.iPtr ) < ( markerLength - KMarkerLength ) )
+ {
+ // Underflow, backup the iterator to the beginning of the marker
+ iReader.iPtr -= KMarkerMinLength;
+ return EFrameIncomplete;
+ }
+
+ TPLTMarker *pltMarker = new ( ELeave ) TPLTMarker;
+ //CleanupStack::PushL( pltMarker );
+ CleanupDeletePushL( pltMarker );
+
+ pltMarker->iZplt = *iReader.iPtr++;
+
+ TInt entries = markerLength - KMarkerSize - 1;
+ while ( entries )
+ {
+ User::LeaveIfError( pltMarker->iIplt.Append( *iReader.iPtr++ ) );
+ --entries;
+ }
+
+ // Make sure we read all the data
+ if ( ( iReader.iPtr - iReader.iPtrStartMarker ) != ( markerLength + KMarkerSize ) )
+ {
+ // We must be missing some data in the marker
+ User::Leave( KErrCorrupt );
+ }
+
+ CJ2kTileInfo& tile = CONST_CAST( CJ2kTileInfo&, iImageInfo->TileAt( iLastTileIndex ) );
+
+ // Append PLT to the current tile and decrement the tile length
+ tile.AppendPLTL( pltMarker, markerLength + KMarkerSize );
+ CleanupStack::Pop();
+
+ // Any valid marker may come after PLT marker
+ iFHState = EStateInUnknown;
+
+ return EFrameComplete;
+ }
+
+// -----------------------------------------------------------------------------
+// CJp2kReadCodec::ReadSkipTileL
+// Ignore the content and advance the iterator to the next marker.
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+TFrameState CJp2kReadCodec::ReadSkipTileL()
+ {
+ if ( (TUint32)( iReader.iPtrEnd - iReader.iPtr ) < iReader.iSkipLength )
+ {
+ iReader.iSkipLength -= ( iReader.iPtrEnd - iReader.iPtr );
+ iReader.iPtr = iReader.iPtrEnd;
+
+ // Stay in the current state
+ return EFrameIncomplete;
+ }
+ else
+ {
+ if ( iReader.iSkipLength )
+ {
+ iReader.iPtr += iReader.iSkipLength;
+ iReader.iSkipLength = 0;
+ }
+ else
+ {
+ iFHState = EStateInUnknown;
+ }
+ return EFrameComplete;
+ }
+ }
+
+// -----------------------------------------------------------------------------
+// CJp2kReadCodec::UpdateStateFromMarkerL
+// Update the current state according to the marker type.
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+TFrameState CJp2kReadCodec::UpdateStateFromMarkerL()
+ {
+ if ( ( iReader.iPtrEnd - iReader.iPtr ) < KMarkerSize )
+ {
+ // Underflow
+ return EFrameIncomplete;
+ }
+
+ TUint16 marker = PtrReadUtil::ReadBigEndianUint16( iReader.iPtr );
+ switch ( marker )
+ {
+ case KCOD:
+ {
+ iFHState = EStateInCOD;
+ break;
+ }
+ case KCOC:
+ {
+ iFHState = EStateInCOC;
+ break;
+ }
+ case KQCD:
+ {
+ iFHState = EStateInQCD;
+ break;
+ }
+ case KQCC:
+ {
+ iFHState = EStateInQCC;
+ break;
+ }
+ case KRGN:
+ {
+ iFHState = EStateInRGN;
+ break;
+ }
+ case KPOC:
+ {
+ iFHState = EStateInPOC;
+ break;
+ }
+ case KPPM:
+ {
+ iFHState = EStateInPPM;
+ break;
+ }
+ case KTLM:
+ {
+ iFHState = EStateInTLM;
+ break;
+ }
+ case KPLM:
+ {
+ iFHState = EStateInPLM;
+ break;
+ }
+ case KCRG:
+ {
+ iFHState = EStateInCRG;
+ break;
+ }
+ case KCME:
+ {
+ iFHState = EStateInCOM;
+ break;
+ }
+ case KSOT:
+ {
+ iFHState = EStateInSOT;
+ break;
+ }
+ case KPPT:
+ {
+ iFHState = EStateInPPT;
+ break;
+ }
+ case KPLT:
+ {
+ iFHState = EStateInPLT;
+ break;
+ }
+ case KSOD:
+ {
+ iFHState = EStateInSOD;
+ break;
+ }
+ case KEOC:
+ {
+ if ( !iUseNewTile && iImageInfo->TileCount() )
+ {
+ // There is a tile which has not been decoded yet
+ CJ2kTileInfo& tile = CONST_CAST( CJ2kTileInfo&, iImageInfo->TileAt( iLastTileIndex ) );
+
+ tile.DoReleaseUnusedMarkers();
+
+ // Decode and delete the tile
+ DecodeAndDeleteTileL( tile );
+
+ // Start with new tile
+ iUseNewTile = ETrue;
+ if ( !iUseNextTile )
+ {
+ iFHState = EStateInUnknown;
+ return EFrameIncompleteRepositionRequest;
+ }
+ else
+ {
+ if ( !iSequential )
+ {
+ // Must be End of Codestream EOC
+ iFHState = EStateInEOC;
+ iReader.iPtr += KMarkerSize;
+ return EFrameComplete;
+ }
+ }
+ }
+ else
+ {
+ iFHState = EStateInEOC;
+
+ // Have to increment the iterator
+ iReader.iPtr += KMarkerSize;
+ }
+ break;
+ }
+ default:
+ {
+ if ( marker < KEXTS || marker > KEXTE )
+ {
+ // Unrecognized marker
+ User::Leave( KErrCorrupt );
+ }
+ else
+ {
+ // Ignore the extension marker
+ iReader.iPtr += KMarkerSize;
+ }
+ break;
+ }
+ }
+ return EFrameComplete;
+ }
+
+// -----------------------------------------------------------------------------
+// CJp2kReadCodec::DecodeAndDeleteTileL
+// Decode the tile, write to image processor and delete the tile.
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+void CJp2kReadCodec::DecodeAndDeleteTileL( CJ2kTileInfo& aTile )
+ {
+ if ( !iEntropy )
+ {
+ iEntropy = CJ2kEntropyDecoder::NewL( *iImageInfo );
+ }
+
+ if ( !iImageWriter )
+ {
+ iImageWriter = CJ2kImageWriter::NewL( ImageProcessor( ), *iImageInfo, CONST_CAST( TJ2kInfo&,iJ2kInfo ) );
+ }
+
+ if ( !iSynthesis )
+ {
+ iSynthesis = new ( ELeave ) CJ2kSynthesis;
+ }
+
+ if ( iStyleUsed == EUnknownDecoder )
+ {
+ // Use tile-based as the default
+ iStyleUsed = ETileBasedDecoder;
+
+ // If extra levels are dropped, the resolution of the decoded image is larger than
+ // the resolution of the output image. levelsDropped here gives the resolution of
+ // the decoded image (and thus relates to the amount of memory required for decoding).
+ TUint8 levelsDropped = (TUint8)(iImageInfo->LevelDrop() - iImageInfo->ExtraLevelDrop());
+
+ TSizMarker& sizMarker = CONST_CAST( TSizMarker&, iImageInfo->SizMarker() );
+ if ( ( sizMarker.iXTsiz >> levelsDropped ) > (TUint32) KWaveletBlockSize ||
+ ( sizMarker.iYTsiz >> levelsDropped ) > (TUint32) KWaveletBlockSize )
+ {
+ iStyleUsed = EBlockBasedDecoder;
+ }
+ }
+
+ if ( iStyleUsed == ETileBasedDecoder )
+ {
+ iSynthesis->DecodeTileL( *iImageWriter, *iEntropy, *iImageInfo, aTile );
+ }
+ else
+ {
+ iSynthesis->DecodeTileBlockL( *iImageWriter, *iEntropy, *iImageInfo, aTile );
+ }
+
+ iImageInfo->Remove( 0 );
+ }
+
+// -----------------------------------------------------------------------------
+// CJp2kReadCodec::ConvertImageDataL
+// Convert some metadata from file format to TImageDataBlock derived objects
+// and let the framework managing the buffer
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+void CJp2kReadCodec::ConvertImageDataL()
+ {
+ TJ2kInfo& info = CONST_CAST( TJ2kInfo&, iJ2kInfo );
+
+ TInt index;
+ // Convert each IPR box to TJp2kIprBox image data
+ for ( index = 0; index < info.iIPRList.Count(); ++index )
+ {
+ TJp2kIprBox* jp2kIPR = new (ELeave) TJp2kIprBox;
+ CleanupDeletePushL( jp2kIPR );
+
+ jp2kIPR->iIprData = info.iIPRList[index];
+
+ User::LeaveIfError( iFrameData->AppendImageData( jp2kIPR ) );
+ CleanupStack::Pop(); // jp2kIPR
+
+ // Transfer the ownership of the buffer to the framework
+ User::LeaveIfError( iFrameData->AppendImageBuffer( jp2kIPR->iIprData ) );
+ info.iIPRList[index] = 0;
+ }
+ info.iIPRList.Reset();
+
+ // Convert each XML box to TJp2kXmlBox image data
+ for ( index = 0; index < info.iXMLList.Count(); ++index )
+ {
+ TJp2kXmlBox* jp2kXML = new (ELeave) TJp2kXmlBox;
+ CleanupDeletePushL( jp2kXML );
+
+ jp2kXML->iXmlData = info.iXMLList[index];
+
+ User::LeaveIfError( iFrameData->AppendImageData( jp2kXML ) );
+ CleanupStack::Pop(); // jp2kXML
+
+ // Transfer the ownership of the buffer to the framework
+ User::LeaveIfError( iFrameData->AppendImageBuffer( jp2kXML->iXmlData ) );
+ info.iXMLList[index] = 0;
+ }
+ info.iXMLList.Reset();
+
+ TInt length;
+ const TUint8 *ptr = 0;
+ // Convert each UUID box to TJp2kUuidBox image data
+ for ( index = 0; index < info.iUUIDList.Count(); ++index )
+ {
+ TJp2kUuidBox* jp2kUUID = new (ELeave) TJp2kUuidBox;
+ CleanupDeletePushL( jp2kUUID );
+
+ ptr = info.iUUIDList[index]->Ptr();
+ jp2kUUID->iUuidId.Copy( ptr, KJ2KUuidIDSize );
+
+ // Advance the pointer
+ ptr += KJ2KUuidIDSize;
+
+ length = info.iUUIDList[index]->Length() - KJ2KUuidIDSize;
+ jp2kUUID->iUuidData = HBufC8::NewLC( length );
+ jp2kUUID->iUuidData->Des().Append( ptr, length );
+
+ // Transfer the ownership of the buffer to the framework
+ User::LeaveIfError( iFrameData->AppendImageBuffer( jp2kUUID->iUuidData ) );
+ CleanupStack::Pop( 1 ); // jp2kUUID->iUuidData
+
+ User::LeaveIfError( iFrameData->AppendImageData( jp2kUUID ) );
+ CleanupStack::Pop( 1 ); // jp2kUUID
+ }
+ info.iUUIDList.ResetAndDestroy();
+
+ // Convert each UUIDInfo box to TJp2kUuidInfoBox image data
+ for ( index = 0; index < info.iUUIDInfoListList.Count(); ++index )
+ {
+ TJp2kUuidInfoBox* jp2kUUIDInfo = new (ELeave) TJp2kUuidInfoBox;
+ CleanupDeletePushL( jp2kUUIDInfo );
+
+ if ( info.iUUIDInfoListList[index]->Length() )
+ {
+ ptr = info.iUUIDInfoListList[index]->Ptr();
+ jp2kUUIDInfo->iUuidInfoNu = PtrReadUtil::ReadBigEndianUint16Inc( ptr );
+
+ length = jp2kUUIDInfo->iUuidInfoNu * KJ2KUuidIDSize;
+ jp2kUUIDInfo->iUuidInfoId = HBufC8::NewLC( length );
+ jp2kUUIDInfo->iUuidInfoId->Des().Append( ptr, length );
+ }
+
+ if ( info.iUUIDInfoUrlList[index]->Length() )
+ {
+ ptr = info.iUUIDInfoUrlList[index]->Ptr();
+
+ // 1 byte unsigned integer
+ jp2kUUIDInfo->iUuidInfoVersion = *ptr++;
+
+ // 3 bytes unsigned integer (in little endian)
+ jp2kUUIDInfo->iUuidInfoFlag = *ptr++;
+ jp2kUUIDInfo->iUuidInfoFlag |= ( *ptr++ << 8 );
+ jp2kUUIDInfo->iUuidInfoFlag |= ( *ptr++ << 16 );
+
+ length = info.iUUIDInfoUrlList[index]->Length() - 4;
+ jp2kUUIDInfo->iUuidInfoData = HBufC8::NewLC( length );
+ jp2kUUIDInfo->iUuidInfoData->Des().Append( ptr, length );
+ }
+
+ // Transfer the ownership of the buffer to the framework
+ if ( jp2kUUIDInfo->iUuidInfoData )
+ {
+ User::LeaveIfError( iFrameData->AppendImageBuffer( jp2kUUIDInfo->iUuidInfoData ) );
+ CleanupStack::Pop( 1 ); // jp2kUUIDInfo->iUUidInfoData
+ }
+
+ // Transfer the ownership of the buffer to the framework
+ if ( jp2kUUIDInfo->iUuidInfoId )
+ {
+ User::LeaveIfError( iFrameData->AppendImageBuffer( jp2kUUIDInfo->iUuidInfoId ) );
+ CleanupStack::Pop( 1 ); // jp2kUUIDInfo->iUuidInfoId
+ }
+
+ User::LeaveIfError( iFrameData->AppendImageData( jp2kUUIDInfo ) );
+ CleanupStack::Pop( 1 ); // jp2kUUIDInfo
+ }
+ info.iUUIDInfoListList.ResetAndDestroy();
+ info.iUUIDInfoUrlList.ResetAndDestroy();
+ }