diff -r 000000000000 -r 469c91dae73b imagingmodules/jp2kcodec/Src/JP2KConvert.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/imagingmodules/jp2kcodec/Src/JP2KConvert.cpp Thu Dec 17 09:22:31 2009 +0200 @@ -0,0 +1,2196 @@ +/* +* 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: JPEG2000 image encoder/decoder plugin class. +* +*/ + + +// INCLUDE FILES +#include "JP2KImageUtils.h" +#include "JP2KFormat.h" +#include "JP2KConvert.h" +#include "JP2KStreamReader.h" +#include "JP2KImageClientMain.h" +#include "JP2KCodec.h" +#include +#include +#include +#include +#include +#include <101F862D_extra.rsg> +#include +#include "JP2KUids.hrh" +#include + +// EXTERNAL DATA STRUCTURES + +// EXTERNAL FUNCTION PROTOTYPES + +// CONSTANTS + +// MACROS + +// LOCAL CONSTANTS AND MACROS +_LIT( KJ2KPanicCategory, "J2KConvertPlugin" ); + +// MODULE DATA STRUCTURES + +// LOCAL FUNCTION PROTOTYPES + +// FORWARD DECLARATIONS + +// ============================ MEMBER FUNCTIONS =============================== + +// ----------------------------------------------------------------------------- +// CJp2kDecoder::NewL +// Two-phased constructor. +// ----------------------------------------------------------------------------- +// +CJp2kDecoder* CJp2kDecoder::NewL() + { + return new ( ELeave ) CJp2kDecoder; + } + +// Destructor +CJp2kDecoder::~CJp2kDecoder() + { + // Call base class Cleanup(), else there is a possibility + // of memory leak + CImageDecoderPlugin::Cleanup(); + } + +// ----------------------------------------------------------------------------- +// CJp2kDecoder::ImageType +// Get the image type uid of this plugin. +// (other items were commented in a header). +// ----------------------------------------------------------------------------- +// +void CJp2kDecoder::ImageType( TInt aFrameNumber, TUid& aImageType, TUid& aImageSubType ) const + { + __ASSERT_ALWAYS( aFrameNumber == 0, Panic( EFrameNumberOutOfRange ) ); + + TUid uid = {KImageTypeJ2KUid}; + aImageType = uid; + aImageSubType = KNullUid; + } + +// ----------------------------------------------------------------------------- +// CJp2kDecoder::NumberOfImageComments +// Get the number of image comment. +// ----------------------------------------------------------------------------- +// +TInt CJp2kDecoder::NumberOfImageComments() const + { + __ASSERT_ALWAYS( IsImageHeaderProcessingComplete(), Panic( EHeaderProcessingNotComplete ) ); + + const TUid commentUid = { KJ2KCommentUid }; + const CFrameImageData& frameImageData = FrameData( 0 ); + const TInt imageDataCount = frameImageData.ImageDataCount(); + const TImageDataBlock *imageData = 0; + TInt imageCommentCount = 0; + for ( TInt index = 0; index < imageDataCount; ++index ) + { + imageData = frameImageData.GetImageData( index ); + if ( imageData->DataType() == commentUid ) + { + imageCommentCount++; + } + } + return imageCommentCount; + } + +// ----------------------------------------------------------------------------- +// CJp2kDecoder::ImageCommentL +// Get the image comment. +// (other items were commented in a header). +// ----------------------------------------------------------------------------- +// +HBufC* CJp2kDecoder::ImageCommentL( TInt aCommentNumber ) const + { + __ASSERT_ALWAYS( IsImageHeaderProcessingComplete(), Panic( EHeaderProcessingNotComplete ) ); + __ASSERT_ALWAYS( ( aCommentNumber >= 0 ) && ( aCommentNumber < NumberOfImageComments() ), + Panic( ECommentNumberOutOfRange ) ); + + HBufC *comment = 0; + + if( FrameData( 0 ).ImageDataCount() > 0 ) + { + const TUid commentUid = { KJ2KCommentUid }; + const CFrameImageData& frameImageData = FrameData( 0 ); + const TInt imageDataCount = frameImageData.ImageDataCount(); + const TImageDataBlock *imageData = 0; + TInt commentCount = 0; + for ( TInt index = 0; index < imageDataCount; ++index ) + { + imageData = frameImageData.GetImageData( index ); + if ( imageData->DataType() == commentUid ) + { + if ( commentCount == aCommentNumber ) + { + index = imageDataCount; // Break from the for loop + } + else + { + commentCount++; + } + } + } + + if( imageData != 0 ) + { + const TJp2kComment *jp2kComment = STATIC_CAST( const TJp2kComment*, imageData ); + comment = HBufC::NewL( jp2kComment->iComment->Length() ); + + // Create 16 bit copy of the 8 bit original + comment->Des().Copy( *( jp2kComment->iComment ) ); + } + } + return comment; + } + +// ----------------------------------------------------------------------------- +// CJp2kDecoder::NumberOfFrameComments +// Get the number of frame comment. +// (other items were commented in a header). +// ----------------------------------------------------------------------------- +// +TInt CJp2kDecoder::NumberOfFrameComments( TInt aFrameNumber ) const + { + __ASSERT_ALWAYS( IsImageHeaderProcessingComplete(), Panic( EHeaderProcessingNotComplete ) ); + __ASSERT_ALWAYS( aFrameNumber == 0, Panic( EFrameNumberOutOfRange ) ); + + return NumberOfImageComments(); + } + +// ----------------------------------------------------------------------------- +// CJp2kDecoder::FrameCommentL +// Get the frame comment. +// (other items were commented in a header). +// ----------------------------------------------------------------------------- +// +HBufC* CJp2kDecoder::FrameCommentL( TInt aFrameNumber, TInt aCommentNumber ) const + { + __ASSERT_ALWAYS( IsImageHeaderProcessingComplete(), Panic( EHeaderProcessingNotComplete ) ); + __ASSERT_ALWAYS( aFrameNumber == 0, Panic( EFrameNumberOutOfRange ) ); + + return ImageCommentL( aCommentNumber ); + } + +// ----------------------------------------------------------------------------- +// CJp2kDecoder::FrameInfoStringsL +// Retrieve frame information and format it according to info stored in .rss file. +// (other items were commented in a header). +// ----------------------------------------------------------------------------- +// +CFrameInfoStrings* CJp2kDecoder::FrameInfoStringsL( RFs& aFs, TInt aFrameNumber ) + { + const TUid KJp2kCodecDllUid = { KJ2KCodecDllUidValue }; + + RResourceFile resourceFile; + OpenExtraResourceFileLC( aFs, KJp2kCodecDllUid, resourceFile ); + + HBufC8* resourceInfo = resourceFile.AllocReadLC( THEDECODERINFO ); + TResourceReader resourceReader; + resourceReader.SetBuffer( resourceInfo ); + + TBuf info; + TBuf templte; + + const TFrameInfo& frameInfo = FrameInfo( aFrameNumber ); + CFrameInfoStrings* frameInfoStrings = CFrameInfoStrings::NewLC(); + + info = resourceReader.ReadTPtrC(); + frameInfoStrings->SetDecoderL( info ); + + info = resourceReader.ReadTPtrC(); + frameInfoStrings->SetFormatL( info ); + + TInt width = frameInfo.iOverallSizeInPixels.iWidth; + TInt height = frameInfo.iOverallSizeInPixels.iHeight; + TInt depth = frameInfo.iBitsPerPixel; + + templte = resourceReader.ReadTPtrC(); + info.Format( templte, width, height ); + frameInfoStrings->SetDimensionsL( info ); + + CDesCArrayFlat* resourceArray = resourceReader.ReadDesCArrayL(); + CleanupStack::PushL( resourceArray ); + TUint formatIndex = ( frameInfo.iFlags & TFrameInfo::EColor ) ? 1 : 0; + templte = ( *resourceArray )[formatIndex]; + CleanupStack::PopAndDestroy( resourceArray ); + info.Format( templte, depth ); + frameInfoStrings->SetDepthL( info ); + + resourceArray = resourceReader.ReadDesCArrayL(); + CleanupStack::PushL( resourceArray ); + formatIndex = 0; + info = ( *resourceArray )[formatIndex]; + CleanupStack::PopAndDestroy( resourceArray ); + frameInfoStrings->SetDetailsL( info ); + + CleanupStack::Pop( frameInfoStrings ); + CleanupStack::PopAndDestroy( 2 ); // resourceInfo + resourceFile + return frameInfoStrings; + } + +// ----------------------------------------------------------------------------- +// CJp2kDecoder::FrameHeaderBlockSize +// Returns the frame header block size. +// (other items were commented in a header). +// ----------------------------------------------------------------------------- +// +TInt CJp2kDecoder::FrameHeaderBlockSize( TInt aFrameNumber ) const + { + __ASSERT_ALWAYS( aFrameNumber == 0, Panic( EFrameNumberOutOfRange ) ); + + return KJ2kInputBufferSize; + } + +// ----------------------------------------------------------------------------- +// CJp2kDecoder::FrameBlockSize +// Returns the frame block size. +// (other items were commented in a header). +// ----------------------------------------------------------------------------- +// +TInt CJp2kDecoder::FrameBlockSize(TInt aFrameNumber) const + { + __ASSERT_ALWAYS( aFrameNumber == 0, Panic( EFrameNumberOutOfRange ) ); + + return KJ2kInputBufferSize; + } + +// ----------------------------------------------------------------------------- +// CJp2kDecoder::DoConvert +// Override the default DoConvert to split out the parsing and decoding +// process into multiple steps. +// (other items were commented in a header). +// ----------------------------------------------------------------------------- +// +void CJp2kDecoder::DoConvert() + { + TFrameState codecState = EFrameIncomplete; + TInt errCode = KErrNone; + + CJp2kReadCodec *j2kCodec = static_cast( ImageReadCodec() ); + + if ( !j2kCodec->IsDecodeTile() ) + { + // parsing of a tile-part + TRAP( errCode, PrepareForProcessFrameL() ); + if ( errCode != KErrNone ) + { + RequestComplete( errCode ); + return; + } + + TBufPtr8& sourceData = SourceData(); + TInt sourceLength = sourceData.Length(); + if ( sourceLength != 0 ) + { + TRAP( errCode, codecState = j2kCodec->ProcessFrameL( sourceData ) ); + + if ( j2kCodec->IsDecodeTile() ) + { + // tile-part contains all compressed data + // and proceed to the decoding + SelfComplete( KErrNone ); + return; + } + } + // continue on parsing the tile-part + HandleProcessFrameResult( errCode, codecState ); + } + else + { + // decoding of the tile-part + TRAP( errCode, codecState = j2kCodec->DecodeTileL() ); + + if ( errCode == KErrNone ) + { + if ( j2kCodec->IsDecodeTile() ) + { + // continue on decoding the tile-part + // if we split the decoding into multiple steps + SelfComplete( KErrNone ); + return; + } + } + // either continue on parsing the next tile-part + // or done with the whole image + HandleProcessFrameResult( errCode, codecState ); + } + } + +// ----------------------------------------------------------------------------- +// CJp2kDecoder::CJp2kDecoder +// C++ default constructor can NOT contain any code, that +// might leave. +// ----------------------------------------------------------------------------- +// +CJp2kDecoder::CJp2kDecoder() + { + } + +// ----------------------------------------------------------------------------- +// CJp2kDecoder::ReadFormatL +// JP2 File Format detection state machine. +// (other items were commented in a header). +// ----------------------------------------------------------------------------- +// +void CJp2kDecoder::ReadFormatL() + { + // Verify the JP2 file format if it exist + iCallFromFramework = ETrue; + + while ( iState != EStateInCodestreamBox ) + { + switch ( iState ) + { + case EStateInSignatureBox: + { + ReadSignatureBoxL(); + break; + } + case EStateInFileTypeBox: + { + ReadFileTypeBoxL(); + break; + } + case EStateInJP2SuperBox: + { + ReadJp2HeaderBoxL(); + break; + } + case EStateInIPRBox: + { + ReadIPRBoxL(); + break; + } + case EStateInXMLBox: + { + ReadXMLBoxL(); + break; + } + case EStateInUUIDBox: + { + ReadUUIDBoxL(); + break; + } + case EStateInUUIDInfoBox: + { + ReadUUIDInfoBoxL(); + break; + } + case EStateInUnknown: + { + if ( iCallFromFramework ) + { + // Always read the length and type of the box + ReadDataL( iLastRead, iBufferDes, KJ2kBoxTypeLength ); + + if ( (TUint32)iBufferDes.Length() < KJ2kBoxTypeLength ) + { + if ( ( iJ2kInfo.iCSOffset != 0 ) && + ( (TUint32)iBufferDes.Length() == 0 ) ) + { + // We have reach the end of file/stream and + // CodeStream box has been recognized + iState = EStateInCodestreamBox; + } + else + { + // Need more data from the ICL framework + User::Leave( KErrUnderflow ); + } + } + iPtr = iBufferDes.Ptr(); + } + + if ( iState != EStateInCodestreamBox ) + { + // Length and Type of next box + iBoxLength = PtrReadUtil::ReadBigEndianUint32Inc( iPtr ); + iBoxType = PtrReadUtil::ReadBigEndianUint32( iPtr ); + + // Update the internal state based on the iBoxType + UpdateStateFromBoxTypeL(); + + if ( iState != EStateInCodestreamBox ) + { + // Corrupted box length + if ( ( (TInt32)iBoxLength ) < 0 ) + { + User::Leave( KErrCorrupt ); + } + } + } + break; + } + default: + { + break; + } + } + iCallFromFramework = EFalse; + } + + // When the code reach here, it means that we have found the + // codestream box in JP2 file format or the codestream SOC itself + // in case of the JP2 file format, all the boxes after the + // codestream box will not be read and parsed. + + // In JP2 file format, iLastRead points to codestream box + // in JP2 codestream, iLastRead points to SOC marker + // it is the offset that ICL framework used to read + // in more data from the image file. + SetStartPosition( iJ2kInfo.iCSOffset ); + + // Always set the image data length to KMaxTInt32 + SetDataLength( KMaxTInt ); + + // Fill up the image related information, if it is + // in JP2 file format, else defer the setting of the + // image info til SIZ marker in the codestream has + // been processed. + if ( iJ2kInfo.iOption & TJ2kInfo::EJP2file ) + { + TFrameInfo& imageInfo = CONST_CAST( TFrameInfo&, ImageInfo() ); + imageInfo.iOverallSizeInPixels = iJ2kInfo.iImageSize; + imageInfo.iFrameCoordsInPixels.SetRect( TPoint( 0, 0 ), iJ2kInfo.iImageSize ); + imageInfo.iFrameSizeInTwips = iJ2kInfo.iImageSizeInTwips; + + if ( iJ2kInfo.iBPCList.Count() > 0 ) + { + // Calculate based on the bitdepth per component + for ( TUint16 index = 0; index < iJ2kInfo.iNC; ++index ) + { + imageInfo.iBitsPerPixel += ( ( 0x7f & iJ2kInfo.iBPCList[index] ) + 1 ); + } + } + else + { + if ( iJ2kInfo.iBPC == KJ2kIsBPCBoxExist ) + { + User::Leave( KErrCorrupt ); + } + + // Has the same bitdepth on each component + imageInfo.iBitsPerPixel = ( ( 0x7f & iJ2kInfo.iBPC ) + 1 ) * iJ2kInfo.iNC; + } + imageInfo.iFlags |= TFrameInfo::ECanDither; + + // Decoder is able to handle scaleable resolution + imageInfo.iFlags |= TFrameInfo::EConstantAspectRatio; + + if ( iJ2kInfo.iEnumCS != KJ2kColourSpecGrayScale ) + { + imageInfo.iFlags |= TFrameInfo::EColor; + } + + // No animation. + imageInfo.iDelay = 0; + + switch ( imageInfo.iBitsPerPixel ) + { + case 1: + { + imageInfo.iFrameDisplayMode = EGray2; + break; + } + case 2: + { + imageInfo.iFrameDisplayMode = EGray4; + break; + } + case 4: + { + imageInfo.iFrameDisplayMode = ( imageInfo.iFlags & TFrameInfo::EColor ) ? EColor16 : EGray16; + break; + } + case 8: + { + imageInfo.iFrameDisplayMode = ( imageInfo.iFlags & TFrameInfo::EColor ) ? EColor16M : EGray256; + break; + } + case 12: + { + imageInfo.iFrameDisplayMode = ( imageInfo.iFlags & TFrameInfo::EColor ) ? EColor4K : EGray256; + break; + } + case 16: + { + imageInfo.iFrameDisplayMode = EColor64K; + break; + } + case 24: + { + imageInfo.iFrameDisplayMode = EColor16M; + break; + } + default: + { + imageInfo.iFrameDisplayMode = EColor64K; + break; + } + } + } + } + +// ----------------------------------------------------------------------------- +// CJp2kDecoder::ReadSignatureBoxL +// Verify and process the Signature box. +// (other items were commented in a header). +// ----------------------------------------------------------------------------- +// +void CJp2kDecoder::ReadSignatureBoxL( ) + { + // Validate the Signature Box + __ASSERT_ALWAYS( iLastRead == 0, Panic( EInvalidState ) ); + + // Read the Signature box + the next box's Length and Type + ReadDataL( iLastRead, iBufferDes, KJ2kFileInformationSize ); + + if ( (TUint32)iBufferDes.Length() < KJ2kSigBoxLength ) + { + // Need more data from the ICL framework + User::Leave( KErrUnderflow ); + } + + iPtr = iBufferDes.Ptr(); + + if ( ( PtrReadUtil::ReadBigEndianUint32Inc( iPtr ) != KJ2kSigBoxLength ) || + ( PtrReadUtil::ReadBigEndianUint32Inc( iPtr ) != KJ2kSigBoxType ) || + ( PtrReadUtil::ReadBigEndianUint32Inc( iPtr ) != KJ2kSigBoxContent ) ) + { + // Unrecognized signature box + User::Leave( KErrCorrupt ); + } + + // File Type box shall immediately follow the Signature box + iLastRead = KJ2kSigBoxLength; + iState = EStateInFileTypeBox; + + // JP2 file format + iJ2kInfo.iOption |= TJ2kInfo::EJP2file; + + if ( iBufferDes.Length() < KJ2kFileInformationSize ) + { + // Need more data from the ICL framework + User::Leave( KErrUnderflow ); + } + } + +// ----------------------------------------------------------------------------- +// CJp2kDecoder::ReadFileTypeBoxL +// Verify and process the File Type box. +// (other items were commented in a header). +// ----------------------------------------------------------------------------- +// +void CJp2kDecoder::ReadFileTypeBoxL() + { + // Validate the File Type Box's Length and Type + if ( iCallFromFramework ) + { + __ASSERT_ALWAYS( iLastRead == KJ2kSigBoxLength, Panic( EInvalidState ) ); + + ReadDataL( iLastRead, iBufferDes, KJ2kBoxTypeLength ); + + if ( (TUint32)iBufferDes.Length() < KJ2kBoxTypeLength ) + { + // Need more data from the ICL framework + User::Leave( KErrUnderflow ); + } + + iPtr = iBufferDes.Ptr(); + } + + iBoxLength = PtrReadUtil::ReadBigEndianUint32Inc( iPtr ); + iBoxType = PtrReadUtil::ReadBigEndianUint32( iPtr ); + + if ( ( (TInt32)iBoxLength ) <= 0 || iBoxType != KJ2kFileTypeBox || iBoxLength > KJ2kFileTypeBoxMaxLength ) + { + // Unrecognized file type box or corrupted box length + User::Leave( KErrCorrupt ); + } + + TUint8 xlBoxExist = 0; + if ( iBoxLength == 1 ) + { + // The XLBox shall exist and contains the actual length of the box + // XLBox is 8 bytes width + ReadDataL( iLastRead + KJ2kBoxTypeLength, iBufferDes, KJ2kBoxTypeLength ); + + if ( (TUint32)iBufferDes.Length() < KJ2kBoxTypeLength ) + { + // Need more data from the ICL framework + User::Leave( KErrUnderflow ); + } + + iPtr = iBufferDes.Ptr(); + iBoxLength = PtrReadUtil::ReadBigEndianUint32Inc( iPtr ); + iBoxLength += PtrReadUtil::ReadBigEndianUint32( iPtr ); + xlBoxExist = 1; + } + + if ( ( (TInt32)iBoxLength ) <= 0 || ( ( (TInt32)iBoxLength - 16 ) / 4 ) <= 0 ) + { + // Must include at least one CL field in the Compatibility list + User::Leave( KErrCorrupt ); + } + + // Read the File Type box + the next box's Length and Type + ReadDataL( iLastRead + KJ2kBoxTypeLength, iBufferDes, iBoxLength ); + + if ( (TUint32)iBufferDes.Length() < iBoxLength - KJ2kBoxTypeLength ) + { + // Need more data from the ICL framework + User::Leave( KErrUnderflow ); + } + + iPtr = iBufferDes.Ptr(); + + // Substract next box's KJ2kBoxTypeLength + const TUint8 *ptrLimit = iPtr + iBoxLength - KJ2kBoxTypeLength; + + // Advance the pointer by 8 bytes if XLBox exists + iPtr += ( xlBoxExist * KJ2kBoxTypeLength ); + + // Check Brand ( BR ) or Major Version + if ( PtrReadUtil::ReadBigEndianUint32Inc( iPtr ) != KJ2kFileTypeBrand ) + { + // It is ok at this point if Major Version does not match + iPtr += 0; + } + + // Check Minor Version ( MinV ) + if ( PtrReadUtil::ReadBigEndianUint32Inc( iPtr ) != KJ2kFileTypeMinV ) + { + // It is ok at this point if Minor Version does not match + iPtr += 0; + } + + // Check Compatibility List ( CL ) + TBool clFound = EFalse; + TUint32 clField = 0; + while ( ( iPtr + 4 ) <= ptrLimit ) + { + clField = PtrReadUtil::ReadBigEndianUint32Inc( iPtr ); + if ( clField == KJ2kFileTypeBrand ) + { + clFound = ETrue; + } + else if ( clField == KJ2kFileTypeProfile0 ) + { + iJ2kInfo.iOption |= TJ2kInfo::EProfile0; + } + else if ( clField == KJ2kFileTypeProfile1 ) + { + iJ2kInfo.iOption |= TJ2kInfo::EProfile1; + } + else + { + // other file types require no action + } + } + + if ( !clFound || iPtr != ptrLimit ) + { + // Unrecognized compatibility list or data misaligned + User::Leave( KErrCorrupt ); + } + + iLastRead += iBoxLength; + iState = EStateInUnknown; + + if ( (TUint32)iBufferDes.Length() < iBoxLength ) + { + // Need more data from the ICL framework + User::Leave( KErrUnderflow ); + } + } + +// ----------------------------------------------------------------------------- +// CJp2kDecoder::ReadJp2HeaderBoxL +// Verify and process the JP2 Header box ( superbox ). +// (other items were commented in a header). +// ----------------------------------------------------------------------------- +// +void CJp2kDecoder::ReadJp2HeaderBoxL() + { + // Since we are getting data from ICL framework + // we have no control of when will be the EOF + if ( iBoxLength == 0 ) + { + User::Leave( KErrCorrupt ); + } + + TUint8 xlBoxExist = 0; + if ( iBoxLength == 1 ) + { + // The XLBox shall exist and contains the actual length of the box + // XLBox is 8 bytes width + ReadDataL( iLastRead + KJ2kBoxTypeLength, iBufferDes, KJ2kBoxTypeLength ); + + if ( (TUint32)iBufferDes.Length() < KJ2kBoxTypeLength ) + { + // Need more data from the ICL framework + User::Leave( KErrUnderflow ); + } + + iPtr = iBufferDes.Ptr(); + iBoxLength = PtrReadUtil::ReadBigEndianUint32Inc( iPtr ); + iBoxLength += PtrReadUtil::ReadBigEndianUint32( iPtr ); + xlBoxExist = 1; + } + + // Corrupted box length + if ( ( (TInt32)iBoxLength ) <= 0 ) + { + User::Leave( KErrCorrupt ); + } + + // Validate the JP2 Header Super Box + // Read the JP2 box + the next box's Length and Type + ReadDataL( iLastRead + KJ2kBoxTypeLength, iBufferDes, iBoxLength ); + + if ( (TUint32)iBufferDes.Length() < iBoxLength - KJ2kBoxTypeLength ) + { + // Need more data from the ICL framework + User::Leave( KErrUnderflow ); + } + + // Make sure that JP2 Header box contains enough data + // for Image Header box + if ( iBoxLength - KJ2kBoxTypeLength < KJ2kImageHeaderBoxLength ) + { + // Missing Image Header box + User::Leave( KErrCorrupt ); + } + + iPtr = iBufferDes.Ptr(); + + // Advance the pointer by 8 bytes if XLBox exists + iPtr += ( xlBoxExist * KJ2kBoxTypeLength ); + + // Image Header box shall be the first box within JP2 Header box + ReadImageHeaderBoxL(); + + TUint32 subBoxLength = 0; + TUint32 subBoxType = 0; + + // Substract next box's Length and Type + const TUint8 *ptrLimit = iPtr + iBoxLength - KJ2kBoxTypeLength - KJ2kImageHeaderBoxLength; + TInt32 length = ptrLimit - iPtr; + TBool csFound = EFalse; + + while ( length > 0 ) + { + if ( ( ptrLimit - iPtr ) < 8 ) + { + // Not enough room for box data + User::Leave( KErrCorrupt ); + } + + subBoxLength = PtrReadUtil::ReadBigEndianUint32Inc( iPtr ); + subBoxType = PtrReadUtil::ReadBigEndianUint32Inc( iPtr ); + + if ( subBoxLength == 1 ) + { + // The XLBox shall exist and contains the actual length of the box + // XLBox is 8 bytes width + subBoxLength = PtrReadUtil::ReadBigEndianUint32Inc( iPtr ); + subBoxLength += PtrReadUtil::ReadBigEndianUint32Inc( iPtr ); + length -= KJ2kBoxTypeLength; + subBoxLength -= KJ2kBoxTypeLength; + } + + if ( ( (TInt32)subBoxLength ) < 0 || ( subBoxLength <= 8 ) || ( ( iPtr + subBoxLength - KJ2kBoxTypeLength ) > ptrLimit ) ) + { + // Not enough room for subbox data or corrupted subbox length + User::Leave( KErrCorrupt ); + } + + switch ( subBoxType ) + { + case KJ2kColourSpecBoxType: + { + if ( !csFound ) + { + // Colour Spec Box + ReadColorSpecBoxL( subBoxLength ); + csFound = ETrue; + } + else + { + // Ignore the second Colour Spec Box, + // just advance the iterator pointer + iPtr += subBoxLength - KJ2kBoxTypeLength; + } + break; + } + case KJ2kResolutionBoxType: + { + // Resolution box ( superbox ) + ReadResolutionBoxL( ptrLimit, subBoxLength ); + break; + } + case KJ2kBitsPerCompBoxType: + { + // Bits Per Component Box + ReadBitsPerCompBoxL( subBoxLength ); + break; + } + case KJ2kPaletterBoxType: + { + // Palette Box + ReadPaletteBoxL(); + break; + } + case KJ2kComponentMapBoxType: + { + // Component Mapping Box + ReadComponentMapBoxL( subBoxLength ); + break; + } + case KJ2kChannelDefBoxType: + { + // Channel Definition Box + ReadChannelDefBoxL( subBoxLength ); + break; + } + default: + { + // Unrecognized Box + User::Leave( KErrCorrupt ); + break; + } + } + length -= subBoxLength; + } + + iLastRead += iBoxLength; + iState = EStateInUnknown; + + // JP2 Header processed + iJ2kInfo.iOption |= TJ2kInfo::EJP2Header; + + if ( (TUint32)iBufferDes.Length() < iBoxLength ) + { + // Need more data from the ICL framework + User::Leave( KErrUnderflow ); + } + } + +// ----------------------------------------------------------------------------- +// CJp2kDecoder::ReadImageHeaderBoxL +// Verify and process the Image Header box ( in JP2 Header box ). +// (other items were commented in a header). +// ----------------------------------------------------------------------------- +// +void CJp2kDecoder::ReadImageHeaderBoxL() + { + // Validate the Image Header Box + if ( ( PtrReadUtil::ReadBigEndianUint32Inc( iPtr ) != KJ2kImageHeaderBoxLength ) || + ( PtrReadUtil::ReadBigEndianUint32Inc( iPtr ) != KJ2kImageHeaderBoxType ) ) + { + // Unrecognized Image Header box + User::Leave( KErrCorrupt ); + } + + iJ2kInfo.iImageSize.iHeight = (TInt)PtrReadUtil::ReadBigEndianUint32Inc( iPtr ); + iJ2kInfo.iImageSize.iWidth = (TInt)PtrReadUtil::ReadBigEndianUint32Inc( iPtr ); + iJ2kInfo.iNC = PtrReadUtil::ReadBigEndianUint16Inc( iPtr ); + iJ2kInfo.iBPC = *iPtr++; + + if ( (iJ2kInfo.iImageSize.iHeight <= 0) || (iJ2kInfo.iImageSize.iWidth <= 0) || + (iJ2kInfo.iNC == 0) || (iJ2kInfo.iBPC == 0) ) + { + // Corrupted image parameters + User::Leave( KErrCorrupt ); + } + + if ( *iPtr++ != KJ2kImageHeaderCompressionType ) + { + // Unrecognized compression type + User::Leave( KErrCorrupt ); + } + + // Check color space - UnkC + TUint8 value = *iPtr++; + if ( value == 0 || value == 1 ) + { + iJ2kInfo.iOption |= ( value == 0 ) ? TJ2kInfo::EColorSpec : 0; + } + else + { + // Unrecognized color space + User::Leave( KErrCorrupt ); + } + + // Check intellectual property - IPR + value = *iPtr++; + if ( value == 0 || value == 1 ) + { + iJ2kInfo.iOption |= value; + } + else + { + // Unrecognized intellectual property + User::Leave( KErrCorrupt ); + } + } + +// ----------------------------------------------------------------------------- +// CJp2kDecoder::ReadColorSpecBoxL +// Verify and process the Colour Specification box ( in JP2 Header box ). +// (other items were commented in a header). +// ----------------------------------------------------------------------------- +// +void CJp2kDecoder::ReadColorSpecBoxL( const TUint32 aBoxLength ) + { + // Validate the Color Specification Box + TUint8 method = *iPtr++; + + if ( method != 1 && method != 2 ) + { + // Unrecognized method + User::Leave( KErrCorrupt ); + } + + // Ignore the precedence + iPtr++; + + // Ignore the approximation + iPtr++; + + if ( method == 1 ) + { + // Method must be 1 if we reach this point + iJ2kInfo.iEnumCS = PtrReadUtil::ReadBigEndianUint32Inc( iPtr ); + switch ( iJ2kInfo.iEnumCS ) + { + case 16: + case 17: + case 18: + case 21: + case 22: + { + break; + } + default: + { + // Unrecognized colour specification + User::Leave( KErrNotSupported ); + break; + } + } + } + else + { + // ICC profile + TUint32 length = (TUint32)( aBoxLength - KJ2kBoxTypeLength - 3 ); + iJ2kInfo.iICCProfile = HBufC8::NewL( length ); + iJ2kInfo.iICCProfile->Des().Append( iPtr, length ); + iPtr += length; + } + } + +// ----------------------------------------------------------------------------- +// CJp2kDecoder::ReadBitsPerCompBoxL +// Verify and process the Bits Per Component box ( in JP2 Header box ). +// (other items were commented in a header). +// ----------------------------------------------------------------------------- +// +void CJp2kDecoder::ReadBitsPerCompBoxL( TUint32 aBoxLength ) + { + if ( iJ2kInfo.iBPC != KJ2kIsBPCBoxExist ) + { + // Should not happen but we just advance + // the iterator and ignore the whole box + iPtr += aBoxLength - KJ2kBoxTypeLength; + return; + } + + // Validate the Bits Per Component Box + if ( ( aBoxLength - KJ2kBoxTypeLength ) != iJ2kInfo.iNC ) + { + // Unrecognized number of components + User::Leave( KErrCorrupt ); + } + + while ( aBoxLength > KJ2kBoxTypeLength ) + { + User::LeaveIfError( iJ2kInfo.iBPCList.Append( *iPtr++ ) ); + + --aBoxLength; + } + } + +// ----------------------------------------------------------------------------- +// CJp2kDecoder::ReadResolutionBoxL +// Verify and process the Resolution box ( in JP2 Header box, +// (other items were commented in a header). +// ----------------------------------------------------------------------------- +// +void CJp2kDecoder::ReadResolutionBoxL( const TUint8 *aPtrLimit, TUint32 aBoxLength ) + { + TUint32 subBoxLength = 0; + TUint32 subBoxType = 0; + + aBoxLength -= KJ2kBoxTypeLength; + while ( aBoxLength > 0 ) + { + if ( (TUint32)( aPtrLimit - iPtr ) < KJ2kResSubBoxLength ) + { + // Not enough room for subbox data + User::Leave( KErrCorrupt ); + } + + subBoxLength = PtrReadUtil::ReadBigEndianUint32Inc( iPtr ); + subBoxType = PtrReadUtil::ReadBigEndianUint32Inc( iPtr ); + + if ( subBoxLength == 1 ) + { + // The XLBox shall exist and contains the actual length of the box + // XLBox is 8 bytes width + subBoxLength = PtrReadUtil::ReadBigEndianUint32Inc( iPtr ); + subBoxLength += PtrReadUtil::ReadBigEndianUint32Inc( iPtr ); + aBoxLength -= KJ2kBoxTypeLength; + subBoxLength -= KJ2kBoxTypeLength; + } + + if ( subBoxLength != KJ2kResSubBoxLength ) + { + // Corrupted resolution box length, both sub boxes have length of 18 + User::Leave( KErrCorrupt ); + } + + if ( subBoxType == KJ2kCaptureResBoxType ) + { + ReadCaptureResBoxL( subBoxLength ); + } + else if ( subBoxType == KJ2kDisplayResBoxType ) + { + ReadDisplayResBoxL( ); + } + else + { + // Unrecognized box in Resolution super box + User::Leave( KErrCorrupt ); + } + aBoxLength -= subBoxLength; + } + } + +// ----------------------------------------------------------------------------- +// CJp2kDecoder::ReadDisplayResBoxL +// Verify and process the Default Display Resolution box ( in Resolution box ). +// (other items were commented in a header). +// ----------------------------------------------------------------------------- +// +void CJp2kDecoder::ReadDisplayResBoxL() + { + // Store default display resolution + TUint16 verNum = PtrReadUtil::ReadBigEndianUint16Inc( iPtr ); + TUint16 verDen = PtrReadUtil::ReadBigEndianUint16Inc( iPtr ); + TUint16 horNum = PtrReadUtil::ReadBigEndianUint16Inc( iPtr ); + TUint16 horDen = PtrReadUtil::ReadBigEndianUint16Inc( iPtr ); + TUint8 verExp = *iPtr++; + TUint8 horExp = *iPtr++; + TReal tenPow = 0.0; + + // Check the validity of the parameters + if((verNum == 0) || (verDen == 0) || (horNum == 0) || (horDen == 0)) + { + // Values corrupted, do not try to compute the SizeInTwips + return; + } + + User::LeaveIfError( Math::Pow10( tenPow, verExp ) ); + + TReal result = ( iJ2kInfo.iImageSize.iWidth / ( ( (TReal)verNum / verDen ) * tenPow ) ) / KJ2kTwipM; + iJ2kInfo.iImageSizeInTwips.iWidth = (TInt)result; + + User::LeaveIfError( Math::Pow10( tenPow,horExp ) ); + + result = ( iJ2kInfo.iImageSize.iHeight / ( ( (TReal)horNum / horDen ) * tenPow ) ) / KJ2kTwipM; + iJ2kInfo.iImageSizeInTwips.iHeight = (TInt)result; + } + +// ----------------------------------------------------------------------------- +// CJp2kDecoder::ReadCaptureResBoxL +// Verify and process the Capture Resolution box ( in Resolution box ). +// (other items were commented in a header). +// ----------------------------------------------------------------------------- +// +void CJp2kDecoder::ReadCaptureResBoxL( const TUint32 aBoxLength ) + { + // Ignore the capture resolution + iPtr += aBoxLength - KJ2kBoxTypeLength; + } + +// ----------------------------------------------------------------------------- +// CJp2kDecoder::ReadPaletteBoxL +// Verify and process the Palette box ( in JP2 Header box ). +// (other items were commented in a header). +// ----------------------------------------------------------------------------- +// +void CJp2kDecoder::ReadPaletteBoxL() + { + // Validate the Palette Box + TUint16 entries = PtrReadUtil::ReadBigEndianUint16Inc( iPtr ); + TUint8 npc = *iPtr++; + + if((entries > KMaxPaletteEntries) || (entries == 0)) + { + // Number of entries must be between 1 and 1024 + User::Leave( KErrCorrupt ); + } + + TInt rowIndex = 0; + TInt columnIndex = 0; + RArray bpcInBytes; + TUint8 bpc = 0; + + for ( rowIndex = 0; rowIndex < npc; ++rowIndex ) + { + bpc = *iPtr++; + User::LeaveIfError( iJ2kInfo.iPalette.iBList.Append( bpc ) ); + + bpc = (TUint8)( ( 0x7f & bpc ) + 1 ); + User::LeaveIfError( bpcInBytes.Append( (TUint)( ( bpc % 8 ) ? bpc / 8 + 1 : bpc / 8 ) ) ); + } + + RArray *cList; + CleanupClosePushL( bpcInBytes ); + + for ( rowIndex = 0; rowIndex < entries; ++rowIndex ) + { + cList = new ( ELeave ) RArray( npc ); + CleanupStack::PushL( cList ); + CleanupClosePushL( *cList ); + + for ( columnIndex = 0; columnIndex < npc; ++columnIndex ) + { + switch ( bpcInBytes[columnIndex] ) + { + case 1: + { + User::LeaveIfError( cList->Append( (TUint)*iPtr++ ) ); + break; + } + case 2: + { + User::LeaveIfError( cList->Append( (TUint)PtrReadUtil::ReadBigEndianUint16Inc( iPtr ) ) ); + break; + } + case 3: + { + bpc = *iPtr++; + User::LeaveIfError( cList->Append( ( (TUint)bpc << 16 ) | PtrReadUtil::ReadBigEndianUint16Inc( iPtr ) ) ); + break; + } + case 4: + { + User::LeaveIfError( cList->Append( PtrReadUtil::ReadBigEndianUint32Inc( iPtr ) ) ); + break; + } + default: + { + // Unrecognized index + User::Leave( KErrCorrupt ); + break; + } + } + } + User::LeaveIfError( iJ2kInfo.iPalette.iC2DArray.Append( cList ) ); + CleanupStack::Pop(2); + } + CleanupStack::PopAndDestroy(); + } + +// ----------------------------------------------------------------------------- +// CJp2kDecoder::ReadComponentMapBoxL +// Verify and process the Component Mapping box ( in JP2 Header box ). +// (other items were commented in a header). +// ----------------------------------------------------------------------------- +// +void CJp2kDecoder::ReadComponentMapBoxL( TUint32 aBoxLength ) + { + // Validate the Component Mapping Box + if ( ( aBoxLength - KJ2kBoxTypeLength ) % 4 != 0 ) + { + // Misaligned Component Mapping box + User::Leave( KErrCorrupt ); + } + + TUint16 cmp = 0; + TUint8 mtyp = 0; + TUint8 pcol = 0; + + while ( aBoxLength > KJ2kBoxTypeLength ) + { + cmp = PtrReadUtil::ReadBigEndianUint16Inc( iPtr ); + + if(cmp > KMaxComponents) + { + // Illegal component index + User::Leave( KErrCorrupt ); + } + + mtyp = *iPtr++; + pcol = *iPtr++; + if ( mtyp == 0 || mtyp == 1 ) + { + if ( mtyp == 0 && pcol != 0 ) + { + // Unrecognized matching between MTYP and PCOL + User::Leave( KErrCorrupt ); + } + } + else + { + // Unrecognized MTYP + User::Leave( KErrCorrupt ); + } + + User::LeaveIfError( iJ2kInfo.iCMPList.Append( TComponentMap( cmp, mtyp, pcol ) ) ); + aBoxLength -= 4; + } + } + +// ----------------------------------------------------------------------------- +// CJp2kDecoder::ReadChannelDefBoxL +// Verify and process the Channel Definition box ( in JP2 Header box ). +// (other items were commented in a header). +// ----------------------------------------------------------------------------- +// +void CJp2kDecoder::ReadChannelDefBoxL( TUint32 aBoxLength ) + { + // Validate the Channel Definition Box + TUint16 entries = PtrReadUtil::ReadBigEndianUint16Inc( iPtr ); + if ( ( aBoxLength - KJ2kBoxTypeLength - 2 ) / 6 != entries ) + { + // Misaligned Channel Definition box + User::Leave( KErrCorrupt ); + } + + TUint16 cn = 0; + TUint16 typ = 0; + TUint16 asoc = 0; + + while ( entries != 0 ) + { + cn = PtrReadUtil::ReadBigEndianUint16Inc( iPtr ); + typ = PtrReadUtil::ReadBigEndianUint16Inc( iPtr ); + asoc = PtrReadUtil::ReadBigEndianUint16Inc( iPtr ); + User::LeaveIfError( iJ2kInfo.iCNList.Append( TChannelDefinition( cn, typ, asoc ) ) ); + --entries; + } + } + +// ----------------------------------------------------------------------------- +// CJp2kDecoder::ReadIPRBoxL +// Verify and process the IPR box . +// (other items were commented in a header). +// ----------------------------------------------------------------------------- +// +void CJp2kDecoder::ReadIPRBoxL() + { + // Check whether this IPR box is the last box in the file + if ( iBoxLength == 0 ) + { + // This IPR box is the last box in the file + if ( iJ2kInfo.iCSOffset != 0 ) + { + // CodeStream box has been recognized + // Since we are not able to read til the + // end of file/stream, we will skip this + // IPR box + iState = EStateInCodestreamBox; + return; + } + else + { + // The CodeStream box is missing from the file + // and nothing can be decoded + User::Leave( KErrCorrupt ); + } + } + + TUint xlBoxExist = 0; + if ( iBoxLength == 1 ) + { + // The XLBox shall exist and contains the actual length of the box + // XLBox is 8 bytes width + ReadDataL( iLastRead + KJ2kBoxTypeLength, iBufferDes, KJ2kBoxTypeLength ); + + if ( (TUint32)iBufferDes.Length() < KJ2kBoxTypeLength ) + { + // Need more data from the ICL framework + User::Leave( KErrUnderflow ); + } + + iPtr = iBufferDes.Ptr(); + iBoxLength = PtrReadUtil::ReadBigEndianUint32Inc( iPtr ); + iBoxLength += PtrReadUtil::ReadBigEndianUint32( iPtr ); + xlBoxExist = 1; + } + + // Corrupted box length + if ( ( (TInt32)iBoxLength ) < 0 ) + { + User::Leave( KErrCorrupt ); + } + + // Check whether this IPR box is the last box in the file + if ( iBoxLength == 0 ) + { + // This IPR box is the last box in the file + if ( iJ2kInfo.iCSOffset != 0 ) + { + // CodeStream box has been recognized + // Since we are not able to read til the + // end of file/stream, we will skip this + // IPR box + iState = EStateInCodestreamBox; + return; + } + else + { + // The CodeStream box is missing from the file + // and nothing can be decoded + User::Leave( KErrCorrupt ); + } + } + + // Validate the IPR Box + // Read the IPR box + the next box's Length and Type + ReadDataL( iLastRead + KJ2kBoxTypeLength, iBufferDes, iBoxLength ); + + if ( (TUint32)iBufferDes.Length() < iBoxLength - KJ2kBoxTypeLength ) + { + // Need more data from the ICL framework + User::Leave( KErrUnderflow ); + } + + iPtr = iBufferDes.Ptr(); + + // Advance the pointer by 8 bytes if XLBox exists + iPtr += ( xlBoxExist * KJ2kBoxTypeLength ); + + TInt length = iBoxLength - ( ( 1 + xlBoxExist ) * KJ2kBoxTypeLength ); + + HBufC8 *iprBuffer = HBufC8::NewLC( length ); + iprBuffer->Des().Append( iPtr, length ); + iPtr += length; + + User::LeaveIfError( iJ2kInfo.iIPRList.Append( iprBuffer ) ); + CleanupStack::Pop(); // iprBuffer + + iLastRead += iBoxLength; + iState = EStateInUnknown; + + if ( (TUint32)iBufferDes.Length() < iBoxLength ) + { + // Test the end of file/stream + ReadDataL( iLastRead, iBufferDes, 1 ); + if ( ( (TUint32)iBufferDes.Length() == 0 ) && + ( iJ2kInfo.iCSOffset != 0 ) ) + { + // CodeStream box has been recognized + iState = EStateInCodestreamBox; + } + else + { + // Need more data from the ICL framework + User::Leave( KErrUnderflow ); + } + } + } + +// ----------------------------------------------------------------------------- +// CJp2kDecoder::ReadXMLBoxL +// Verify and process the XML box. +// (other items were commented in a header). +// ----------------------------------------------------------------------------- +// +void CJp2kDecoder::ReadXMLBoxL() + { + // Check whether this XML box is the last box in the file + if ( iBoxLength == 0 ) + { + // This XML box is the last box in the file + if ( iJ2kInfo.iCSOffset != 0 ) + { + // CodeStream box has been recognized + // Since we are not able to read til the + // end of file/stream, we will skip this + // XML box + iState = EStateInCodestreamBox; + return; + } + else + { + // The CodeStream box is missing from the file + // and nothing can be decoded + User::Leave( KErrCorrupt ); + } + } + + TUint xlBoxExist = 0; + if ( iBoxLength == 1 ) + { + // The XLBox shall exist and contains the actual length of the box + // XLBox is 8 bytes width + ReadDataL( iLastRead + KJ2kBoxTypeLength, iBufferDes, KJ2kBoxTypeLength ); + + if ( (TUint32)iBufferDes.Length() < KJ2kBoxTypeLength ) + { + // Need more data from the ICL framework + User::Leave( KErrUnderflow ); + } + + iPtr = iBufferDes.Ptr(); + iBoxLength = PtrReadUtil::ReadBigEndianUint32Inc( iPtr ); + iBoxLength += PtrReadUtil::ReadBigEndianUint32( iPtr ); + xlBoxExist = 1; + } + + // Corrupted box length + if ( ( (TInt32)iBoxLength ) < 0 ) + { + User::Leave( KErrCorrupt ); + } + + // Check whether this XML box is the last box in the file + if ( iBoxLength == 0 ) + { + // This XML box is the last box in the file + if ( iJ2kInfo.iCSOffset != 0 ) + { + // CodeStream box has been recognized + // Since we are not able to read til the + // end of file/stream, we will skip this + // XML box + iState = EStateInCodestreamBox; + return; + } + else + { + // The CodeStream box is missing from the file + // and nothing can be decoded + User::Leave( KErrCorrupt ); + } + } + + // Validate the XML Box + // Read the XML box + the next box's Length and Type + ReadDataL( iLastRead + KJ2kBoxTypeLength, iBufferDes, iBoxLength ); + + if ( (TUint32)iBufferDes.Length() < iBoxLength - KJ2kBoxTypeLength ) + { + // Need more data from the ICL framework + User::Leave( KErrUnderflow ); + } + + iPtr = iBufferDes.Ptr(); + + // Advance the pointer by 8 bytes if XLBox exists + iPtr += ( xlBoxExist * KJ2kBoxTypeLength ); + + TInt length = iBoxLength - ( ( 1 + xlBoxExist ) * KJ2kBoxTypeLength ); + + HBufC8 *xmlBuffer = HBufC8::NewLC( length ); + xmlBuffer->Des().Append( iPtr, length ); + iPtr += length; + + User::LeaveIfError( iJ2kInfo.iXMLList.Append( xmlBuffer ) ); + CleanupStack::Pop(); // xmlBuffer + + iLastRead += iBoxLength; + iState = EStateInUnknown; + + if ( (TUint32)iBufferDes.Length() < iBoxLength ) + { + // Test the end of file + ReadDataL( iLastRead, iBufferDes, 1 ); + if ( ( (TUint32)iBufferDes.Length() == 0 ) && + ( iJ2kInfo.iCSOffset != 0 ) ) + { + // CodeStream box has been recognized + iState = EStateInCodestreamBox; + } + else + { + // Need more data from the ICL framework + User::Leave( KErrUnderflow ); + } + } + } + +// ----------------------------------------------------------------------------- +// CJp2kDecoder::ReadUUIDBoxL +// Verify and process UUID box. +// (other items were commented in a header). +// ----------------------------------------------------------------------------- +// +void CJp2kDecoder::ReadUUIDBoxL() + { + // Check whether this UUID box is the last box in the file + if ( iBoxLength == 0 ) + { + // This UUID box is the last box in the file + if ( iJ2kInfo.iCSOffset != 0 ) + { + // CodeStream box has been recognized + // Since we are not able to read til the + // end of file/stream, we will skip this + // UUID box + iState = EStateInCodestreamBox; + return; + } + else + { + // The CodeStream box is missing from the file + // and nothing can be decoded + User::Leave( KErrCorrupt ); + } + } + + TUint xlBoxExist = 0; + if ( iBoxLength == 1 ) + { + // The XLBox shall exist and contains the actual length of the box + // XLBox is 8 bytes width + ReadDataL( iLastRead + KJ2kBoxTypeLength, iBufferDes, KJ2kBoxTypeLength ); + + if ( (TUint32)iBufferDes.Length() < KJ2kBoxTypeLength ) + { + // Need more data from the ICL framework + User::Leave( KErrUnderflow ); + } + + iPtr = iBufferDes.Ptr(); + iBoxLength = PtrReadUtil::ReadBigEndianUint32Inc( iPtr ); + iBoxLength += PtrReadUtil::ReadBigEndianUint32( iPtr ); + xlBoxExist = 1; + } + + // Corrupted box length + if ( ( (TInt32)iBoxLength ) < 0 ) + { + User::Leave( KErrCorrupt ); + } + + // Check whether this UUID box is the last box in the file + if ( iBoxLength == 0 ) + { + // This UUID box is the last box in the file + if ( iJ2kInfo.iCSOffset != 0 ) + { + // CodeStream box has been recognized + // Since we are not able to read til the + // end of file/stream, we will skip this + // UUID box + iState = EStateInCodestreamBox; + return; + } + else + { + // The CodeStream box is missing from the file + // and nothing can be decoded + User::Leave( KErrCorrupt ); + } + } + + // Validate the UUID Box + // Read the UUID box + the next box's Length and Type + ReadDataL( iLastRead + KJ2kBoxTypeLength, iBufferDes, iBoxLength ); + + if ( (TUint32)iBufferDes.Length() < iBoxLength - KJ2kBoxTypeLength ) + { + // Need more data from the ICL framework + User::Leave( KErrUnderflow ); + } + + iPtr = iBufferDes.Ptr(); + + // Advance the pointer by 8 bytes if XLBox exists + iPtr += ( xlBoxExist * KJ2kBoxTypeLength ); + + TInt length = iBoxLength - ( ( 1 + xlBoxExist ) * KJ2kBoxTypeLength ); + + HBufC8 *uuidBuffer = HBufC8::NewLC( length ); + uuidBuffer->Des().Append( iPtr, length ); + iPtr += length; + + User::LeaveIfError( iJ2kInfo.iUUIDList.Append( uuidBuffer ) ); + CleanupStack::Pop(); // uuidBuffer + + iLastRead += iBoxLength; + iState = EStateInUnknown; + + if ( (TUint32)iBufferDes.Length() < iBoxLength ) + { + // Test the end of file + ReadDataL( iLastRead, iBufferDes, 1 ); + if ( ( (TUint32)iBufferDes.Length() == 0 ) && + ( iJ2kInfo.iCSOffset != 0 ) ) + { + // CodeStream box has been recognized + iState = EStateInCodestreamBox; + } + else + { + // Need more data from the ICL framework + User::Leave( KErrUnderflow ); + } + } + } + +// ----------------------------------------------------------------------------- +// CJp2kDecoder::ReadUUIDInfoBoxL +// Verify and process the UUID Info box ( superbox ). +// (other items were commented in a header). +// ----------------------------------------------------------------------------- +// +void CJp2kDecoder::ReadUUIDInfoBoxL() + { + // Check whether this UUIDInfo box is the last box in the file + if ( iBoxLength == 0 ) + { + // This UUIDInfo box is the last box in the file + if ( iJ2kInfo.iCSOffset != 0 ) + { + // CodeStream box has been recognized + // Since we are not able to read til the + // end of file/stream, we will skip this + // UUIDInfo box + iState = EStateInCodestreamBox; + return; + } + else + { + // The CodeStream box is missing from the file + // and nothing can be decoded + User::Leave( KErrCorrupt ); + } + } + + TUint xlBoxExist = 0; + if ( iBoxLength == 1 ) + { + // The XLBox shall exist and contains the actual length of the box + // XLBox is 8 bytes width + ReadDataL( iLastRead + KJ2kBoxTypeLength, iBufferDes, KJ2kBoxTypeLength ); + + if ( (TUint32)iBufferDes.Length() < KJ2kBoxTypeLength ) + { + // Need more data from the ICL framework + User::Leave( KErrUnderflow ); + } + + iPtr = iBufferDes.Ptr(); + iBoxLength = PtrReadUtil::ReadBigEndianUint32Inc( iPtr ); + iBoxLength += PtrReadUtil::ReadBigEndianUint32( iPtr ); + xlBoxExist = 1; + } + + // Corrupted box length + if ( ( (TInt32)iBoxLength ) < 0 ) + { + User::Leave( KErrCorrupt ); + } + + // Check whether this UUIDInfo box is the last box in the file + if ( iBoxLength == 0 ) + { + // This UUIDInfo box is the last box in the file + if ( iJ2kInfo.iCSOffset != 0 ) + { + // CodeStream box has been recognized + // Since we are not able to read til the + // end of file/stream, we will skip this + // UUIDInfo box + iState = EStateInCodestreamBox; + return; + } + else + { + // The CodeStream box is missing from the file + // and nothing can be decoded + User::Leave( KErrCorrupt ); + } + } + + // Validate the UUIDInfo Box + // Read the UUIDInfo box + the next box's Length and Type + ReadDataL( iLastRead + KJ2kBoxTypeLength, iBufferDes, iBoxLength ); + + if ( (TUint32)iBufferDes.Length() < iBoxLength - KJ2kBoxTypeLength ) + { + // Need more data from the ICL framework + User::Leave( KErrUnderflow ); + } + + iPtr = iBufferDes.Ptr(); + + // Substract next box's Length and Type + const TUint8 *ptrLimit = iPtr + iBoxLength - KJ2kBoxTypeLength; + + // Advance the pointer by 8 bytes if XLBox exists + iPtr += ( xlBoxExist * KJ2kBoxTypeLength ); + + TUint32 subBoxLength = 0; + TUint32 subBoxType = 0; + + TInt32 length = ptrLimit - iPtr; + TInt32 dataLength = 0; + TInt32 order = 0; + + HBufC8 *listBuffer = 0; + HBufC8 *urlBuffer = 0; + + while ( length > 0 ) + { + if ( ( ptrLimit - iPtr ) < 8 ) + { + // Not enough room for box data + User::Leave( KErrCorrupt ); + } + + subBoxLength = PtrReadUtil::ReadBigEndianUint32Inc( iPtr ); + subBoxType = PtrReadUtil::ReadBigEndianUint32Inc( iPtr ); + + if ( subBoxLength == 1 ) + { + // The XLBox shall exist and contains the actual length of the box + // XLBox is 8 bytes width + subBoxLength = PtrReadUtil::ReadBigEndianUint32Inc( iPtr ); + subBoxLength += PtrReadUtil::ReadBigEndianUint32Inc( iPtr ); + length -= KJ2kBoxTypeLength; + subBoxLength -= KJ2kBoxTypeLength; + } + + if ( ( (TInt32)subBoxLength < 0 ) || ( subBoxLength <= 8 ) || ( ( iPtr + subBoxLength - KJ2kBoxTypeLength ) > ptrLimit ) ) + { + // Not enough room for subbox data or corrupted subbox length + User::Leave( KErrCorrupt ); + } + + switch ( subBoxType ) + { + case KJ2kUUIDListBoxType: + { + // Validate the UUIDInfo List box + // NU | ID-0 | ... | ID-n + // where NU is 2 bytes unsigned specifying the number of IDs + // ID is 16 bytes UUID + TUint16 nuField = PtrReadUtil::ReadBigEndianUint16( iPtr ); + if ( ( subBoxLength - ( 2 + KJ2kBoxTypeLength ) ) != + ( (TUint32)( nuField * KJ2KUuidIDSize ) ) ) + { + // UUIDInfo List box does not confirm to standard format + User::Leave( KErrCorrupt ); + } + + if ( listBuffer ) + { + // There should be one UUIDInfo List box + User::Leave( KErrCorrupt ); + } + + dataLength = subBoxLength - KJ2kBoxTypeLength; + listBuffer = HBufC8::NewLC( dataLength ); + listBuffer->Des().Append( iPtr, dataLength ); + iPtr += ( dataLength ); + + if ( order == 0 ) + { + // Increment the order if UUIDInfo List box come first + ++order; + } + break; + } + case KJ2kUUIDUrlBoxType: + { + // Validate the UUIDInfo Data Entry Url box + if ( urlBuffer ) + { + // There should be one UUIDInfo Data Entry Url box + User::Leave( KErrCorrupt ); + } + + dataLength = subBoxLength - KJ2kBoxTypeLength; + urlBuffer = HBufC8::NewLC( dataLength ); + urlBuffer->Des().Append( iPtr, dataLength ); + iPtr += ( dataLength ); + + if ( order == 0 ) + { + // Decrement the order if UUIDInfo Data Entry Url box come first + --order; + } + break; + } + default: + { + // Unrecognized Box + User::Leave( KErrCorrupt ); + break; + } + } + length -= subBoxLength; + } + + if ( listBuffer || urlBuffer ) + { + if ( !( listBuffer ) ) + { + // Create a dummy place holder + listBuffer = HBufC8::NewLC( 1 ); + } + + if ( !( urlBuffer ) ) + { + // Create a dummy place holder + urlBuffer = HBufC8::NewLC( 1 ); + } + + if ( order < 0 ) + { + // UUIDInfo Data Entry Url box come first + User::LeaveIfError( iJ2kInfo.iUUIDInfoListList.Append( listBuffer ) ); + CleanupStack::Pop( 1 ); // listBuffer + + User::LeaveIfError( iJ2kInfo.iUUIDInfoUrlList.Append( urlBuffer ) ); + CleanupStack::Pop( 1 ); // urlBuffer + } + else + { + // UUIDInfo List box come first + User::LeaveIfError( iJ2kInfo.iUUIDInfoUrlList.Append( urlBuffer ) ); + CleanupStack::Pop( 1 ); // urlBuffer + + User::LeaveIfError( iJ2kInfo.iUUIDInfoListList.Append( listBuffer ) ); + CleanupStack::Pop( 1 ); // listBuffer + } + } + else + { + // UUIDInfo box does not containing any + // UUIDInfo List box or UUIDInfo Data Entry Url box + User::Leave( KErrCorrupt ); + } + + iLastRead += iBoxLength; + iState = EStateInUnknown; + + if ( (TUint32)iBufferDes.Length() < iBoxLength ) + { + // Test the end of file + ReadDataL( iLastRead, iBufferDes, 1 ); + if ( ( (TUint32)iBufferDes.Length() == 0 ) && + ( iJ2kInfo.iCSOffset != 0 ) ) + { + // CodeStream box has been recognized + iState = EStateInCodestreamBox; + } + else + { + // Need more data from the ICL framework + User::Leave( KErrUnderflow ); + } + } + } + +// ----------------------------------------------------------------------------- +// CJp2kDecoder::IgnoreBoxL +// Ignore the content of the box and advance the iterator to the next box. +// (other items were commented in a header). +// ----------------------------------------------------------------------------- +// +void CJp2kDecoder::IgnoreBoxL() + { + // Check whether this box is the last box in the file + if ( iBoxLength == 0 ) + { + // This box is the last box in the file + if ( iJ2kInfo.iCSOffset != 0 ) + { + // CodeStream box has been recognized + // Since we are not able to read til the + // end of file/stream, we will skip this + // box + iState = EStateInCodestreamBox; + return; + } + else + { + // The CodeStream box is missing from the file + // and nothing can be decoded + User::Leave( KErrCorrupt ); + } + } + + if ( iBoxLength == 1 ) + { + // The XLBox shall exist and contains the actual length of the box + // XLBox is 8 bytes width + ReadDataL( iLastRead + KJ2kBoxTypeLength, iBufferDes, KJ2kBoxTypeLength ); + + if ( (TUint32)iBufferDes.Length() < KJ2kBoxTypeLength ) + { + // Need more data from the ICL framework + User::Leave( KErrUnderflow ); + } + + iPtr = iBufferDes.Ptr(); + iBoxLength = PtrReadUtil::ReadBigEndianUint32Inc( iPtr ); + iBoxLength += PtrReadUtil::ReadBigEndianUint32( iPtr ); + } + + // Corrupted box length + if ( ( (TInt32)iBoxLength ) < 0 ) + { + User::Leave( KErrCorrupt ); + } + + // Check whether this box is the last box in the file + if ( iBoxLength == 0 ) + { + // This box is the last box in the file + if ( iJ2kInfo.iCSOffset != 0 ) + { + // CodeStream box has been recognized + // Since we are not able to read til the + // end of file/stream, we will skip this + // box + iState = EStateInCodestreamBox; + return; + } + else + { + // The CodeStream box is missing from the file + // and nothing can be decoded + User::Leave( KErrCorrupt ); + } + } + + // Read and ignore the validation of the box + ReadDataL( iLastRead + KJ2kBoxTypeLength, iBufferDes, iBoxLength ); + + if ( (TUint32)iBufferDes.Length() < iBoxLength - KJ2kBoxTypeLength ) + { + // Need more data from the ICL framework + User::Leave( KErrUnderflow ); + } + + iPtr = iBufferDes.Ptr(); + + iLastRead += iBoxLength; + iState = EStateInUnknown; + + iPtr += iBoxLength - KJ2kBoxTypeLength; + if ( (TUint32)iBufferDes.Length() < iBoxLength ) + { + // Test the end of file + ReadDataL( iLastRead, iBufferDes, 1 ); + if ( ( (TUint32)iBufferDes.Length() == 0 ) && + ( iJ2kInfo.iCSOffset != 0 ) ) + { + // CodeStream box has been recognized + iState = EStateInCodestreamBox; + } + else + { + // Need more data from the ICL framework + User::Leave( KErrUnderflow ); + } + } + } + +// ----------------------------------------------------------------------------- +// CJp2kDecoder::UpdateStateFromBoxTypeL +// Update the current state according to the box type +// (other items were commented in a header). +// ----------------------------------------------------------------------------- +// +void CJp2kDecoder::UpdateStateFromBoxTypeL() + { + switch ( iBoxType ) + { + case KJ2kSigBoxType: + { + iState = EStateInSignatureBox; + break; + } + case KJ2kJP2HeaderBoxType: + { + iState = EStateInJP2SuperBox; + break; + } + case KJ2kCodestreamBoxType: + { + if ( iJ2kInfo.iOption & TJ2kInfo::EJP2file ) + { + if ( !( iJ2kInfo.iOption & TJ2kInfo::EJP2Header ) ) + { + // In JP2 file format, CodeStream box + // can not come before JP2 Header box + User::Leave( KErrCorrupt ); + } + + // Save the CodeStream box's length + iJ2kInfo.iCSBoxLength = iBoxLength; + iJ2kInfo.iCSOffset = iLastRead; + + if ( iBoxLength == 0 ) + { + // CodeStream box is the last box in the file + iState = EStateInCodestreamBox; + } + else + { + // Continue checking any boxes after the CodeStream box + if ( iBoxLength == 1 ) + { + // The XLBox shall exist and contains the actual length of the box + // XLBox is 8 bytes width + ReadDataL( iLastRead + KJ2kBoxTypeLength, iBufferDes, KJ2kBoxTypeLength ); + + if ( (TUint32)iBufferDes.Length() < KJ2kBoxTypeLength ) + { + // Need more data from the ICL framework + User::Leave( KErrUnderflow ); + } + + iPtr = iBufferDes.Ptr(); + iBoxLength = PtrReadUtil::ReadBigEndianUint32Inc( iPtr ); + iBoxLength += PtrReadUtil::ReadBigEndianUint32( iPtr ); + } + + // Corrupted box length + if ( ( (TInt32)iBoxLength ) < 0 ) + { + User::Leave( KErrCorrupt ); + } + + iLastRead += iBoxLength; + // Test the end of file + ReadDataL( iLastRead, iBufferDes, KJ2kBoxTypeLength ); + if ( (TUint32)iBufferDes.Length() == 0 ) + { + // CodeStream box is the last box in the file + iState = EStateInCodestreamBox; + } + else if ( (TUint32)iBufferDes.Length() == KJ2kBoxTypeLength ) + { + iPtr = iBufferDes.Ptr(); + } + else + { + // Need more data from the ICL framework + User::Leave( KErrUnderflow ); + } + } + } + else + { + // CodeStream box must exist in file format only + User::Leave( KErrCorrupt ); + } + break; + } + case KJ2kIPRBoxType: + { + iState = EStateInIPRBox; + break; + } + case KJ2kXMLBoxType: + { + iState = EStateInXMLBox; + break; + } + case KJ2kUUIDBoxType: + { + iState = EStateInUUIDBox; + break; + } + case KJ2kUUIDInfoBoxType: + { + iState = EStateInUUIDInfoBox; + break; + } + default: + { + // Check if the first 4 bytes read + // is SOC + SIZ + if ( iBoxLength == KJ2kSOCType ) + { + if ( iJ2kInfo.iOption & TJ2kInfo::EJP2file ) + { + // JP2 codestream shouldn't in JP2 file format + User::Leave( KErrCorrupt ); + } + + // SOC + SIZ marker - JP2 Codestream + iState = EStateInCodestreamBox; + iJ2kInfo.iCSOffset = iLastRead; + } + else + { + // Unrecognized box type + // there are two ways of handling this + // 1. stop parsing and Leave with an KErrCorrupt error + // User::Leave( KErrCorrupt ); + // 2. just ignore the box and continue on parsing the + // next box. + IgnoreBoxL(); + } + break; + } + } + } + +// ----------------------------------------------------------------------------- +// CJp2kDecoder::ScanDataL +// Called from ICL framework to instantiate decoder and parse header. +// (other items were commented in a header). +// ----------------------------------------------------------------------------- +// +void CJp2kDecoder::ScanDataL() + { + ReadFormatL(); + + ASSERT( ImageReadCodec() == NULL ); + + CJp2kReadCodec* imageReadCodec = CJp2kReadCodec::NewL( iJ2kInfo ); + SetImageReadCodec( imageReadCodec ); + + ReadFrameHeadersL(); + } + +// ========================== OTHER EXPORTED FUNCTIONS ========================= + +// ----------------------------------------------------------------------------- +// Global panic function, From JP2KImageClientMain.h +// ----------------------------------------------------------------------------- +// +GLDEF_C void Panic( TIclPanic aError ) //lint !e759 already in module + { + User::Panic( KJ2KPanicCategory, aError ); + } +