diff -r 000000000000 -r 469c91dae73b imagingmodules/jp2kcodec/Src/JP2KCodec.cpp --- /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 +#include +#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(); + }