diff -r 000000000000 -r 818e61de6cd1 crashanalysercmd/PerfToolsSharedLibraries/Engine/SymbianImageLib/Common/Content/SIContent.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/crashanalysercmd/PerfToolsSharedLibraries/Engine/SymbianImageLib/Common/Content/SIContent.cs Thu Feb 11 15:50:58 2010 +0200 @@ -0,0 +1,377 @@ +/* +* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +* All rights reserved. +* This component and the accompanying materials are made available +* under the terms of "Eclipse Public License v1.0" +* which accompanies this distribution, and is available +* at the URL "http://www.eclipse.org/legal/epl-v10.html". +* +* Initial Contributors: +* Nokia Corporation - initial contribution. +* +* Contributors: +* +* Description: +* +*/ +using System; +using System.Collections.Generic; +using System.Text; +using System.IO; +using System.ComponentModel; +using System.Threading; +using SymbianUtils; +using SymbianUtils.Tracer; +using SymbianUtils.PluginManager; +using SymbianStructuresLib.Uids; +using SymbianStructuresLib.Compression.Common; +using SymbianImageLib.Common.Image; +using SymbianImageLib.Common.Header; +using SymbianImageLib.Common.Streams; +using SymbianImageLib.Common.Factory; + +namespace SymbianImageLib.Common.Content +{ + public abstract class SIContent : DisposableObject, ITracer + { + #region Enumerations + public enum TDecompressionEvent + { + EEventDecompressionStarting = 0, + EEventDecompressionProgress, + EEventDecompressionComplete + } + #endregion + + #region Delegates & events + public delegate void DecompressionEventHandler( TDecompressionEvent aEvent, SIContent aFile, object aData ); + public event DecompressionEventHandler DecompressionEvent; + #endregion + + #region Constructors + protected SIContent( SIImage aImage ) + { + iImage = aImage; + } + #endregion + + #region Framework API + public abstract TSymbianCompressionType CompressionType + { + get; + } + + public abstract string FileName + { + get; + } + + public abstract uint FileSize + { + get; + } + + public abstract uint ContentSize + { + get; + } + + public virtual bool IsRelocationSupported + { + get { return true; } + } + + public virtual TCheckedUid Uid + { + get { return new TCheckedUid(); } + } + + public virtual byte[] GetAllData() + { + return new byte[ 0 ]; + } + + public virtual uint ProvideDataUInt32( uint aAddress ) + { + uint ret = 0; + // + if ( IsContentPrepared == false ) + { + // Cannot provide data if we've not prepared it yet + } + else if ( iDecompressionException == false ) + { + WaitForAsyncOperationCompletion(); + uint resolvedAddress = FixupAddress( aAddress ); + ret = DoProvideDataUInt32( resolvedAddress ); + } + // + return ret; + } + + public virtual ushort ProvideDataUInt16( uint aAddress ) + { + ushort ret = 0; + // + if ( IsContentPrepared == false ) + { + // Cannot provide data if we've not prepared it yet + } + else if ( iDecompressionException == false ) + { + WaitForAsyncOperationCompletion(); + uint resolvedAddress = FixupAddress( aAddress ); + ret = DoProvideDataUInt16( resolvedAddress ); + } + // + return ret; + } + + public virtual bool IsCode + { + get { return true; } + } + + protected virtual void OnRelocationAddressChanged( uint aOld, uint aNew ) + { + } + + protected virtual void DoDecompress() + { + } + + protected virtual uint DoProvideDataUInt32( uint aTranslatedAddress ) + { + throw new NotImplementedException(); + } + + protected virtual ushort DoProvideDataUInt16( uint aTranslatedAddress ) + { + throw new NotImplementedException(); + } + + protected abstract bool GetIsContentPrepared(); + #endregion + + #region API + public void PrepareContent( TSynchronicity aSynchronicity ) + { + if ( CompressionType == TSymbianCompressionType.ENone ) + { + // No content preparation required, so just indicate completion + // immediately. + ReportDecompressionEvent( TDecompressionEvent.EEventDecompressionStarting ); + ReportDecompressionEvent( TDecompressionEvent.EEventDecompressionComplete ); + } + else + { + switch ( aSynchronicity ) + { + case TSynchronicity.ESynchronous: + RunDecompressor(); + break; + case TSynchronicity.EAsynchronous: + // Must take the lock to either create or destroy waiter + lock ( iWaiterSyncRoot ) + { + if ( iWaiter == null ) + { + iWaiter = new AutoResetEvent( false ); + ThreadPool.QueueUserWorkItem( new WaitCallback( RunDecompressionInBackgroundThread ), null ); + break; + } + else + { + // Wait is active, so we are presumably busy... + throw new Exception( "Content is already in preparation" ); + } + } + } + } + } + + public uint RelocationAddress + { + get { return iRelocationAddress; } + set + { + if ( value != iRelocationAddress ) + { + uint old = iRelocationAddress; + iRelocationAddress = value; + OnRelocationAddressChanged( old, iRelocationAddress ); + } + } + } + + public virtual bool IsContentPrepared + { + get + { + bool ret = true; + // + if ( CompressionType != TSymbianCompressionType.ENone ) + { + ret = GetIsContentPrepared(); + } + // + return ret; + } + } + #endregion + + #region Properties + public SIImage Image + { + get { return iImage; } + } + + public SIHeader ImageHeader + { + get { return iImage.Header; } + } + + internal SIStream ImageStream + { + get + { + return iImage.Stream; + } + set { iImage.Stream = value; } + } + #endregion + + #region Event handlers + private void RunDecompressionInBackgroundThread( object aNotUsed ) + { + System.Diagnostics.Debug.Assert( iWaiter != null ); + + // Call derived class to do decompression. Must not throw. + RunDecompressor(); + + // Must do this last so that anybody that is waiting for code to become + // ready is resumed. + // + // Also, we might have been disposed of as a result of the "completion" callback + // so in that case, we will have already set the auto-reset-event during the cleanup. + if ( iWaiter != null ) + { + iWaiter.Set(); + } + } + #endregion + + #region Internal methods + protected void ReportDecompressionEvent( TDecompressionEvent aEvent ) + { + ReportDecompressionEvent( aEvent, null ); + } + + protected void ReportDecompressionEvent( TDecompressionEvent aEvent, object aData ) + { + if ( DecompressionEvent != null ) + { + DecompressionEvent( aEvent, this, aData ); + } + } + + private void RunDecompressor() + { + Trace( "[SIImageContent] RunDecompressor() - START - this: " + FileName ); + ReportDecompressionEvent( TDecompressionEvent.EEventDecompressionStarting ); + // + try + { + DoDecompress(); + } + catch ( Exception e ) + { + Trace( "[SIImageContent] RunDecompressor() - Exception - this: {0}, message: {1}", this.FileName, e.Message ); + Trace( "[SIImageContent] RunDecompressor() - Exception - this: {0}, stack : {1}", this.FileName, e.StackTrace ); + iDecompressionException = true; + } + + // Doing this might cause the disposal of the object + ReportDecompressionEvent( TDecompressionEvent.EEventDecompressionComplete ); + Trace( "[SIImageContent] RunDecompressor() - END - this: " + FileName ); + } + + private void WaitForAsyncOperationCompletion() + { + // If the worker doesn't exist then we've already completed the operation + if ( iWaiter != null ) + { + // Just wait on the auto-reset event. If it's already been signalled, then + // we will continue immediately. + iWaiter.WaitOne(); + + // Must take the lock to either create or destroy waiter + lock ( iWaiterSyncRoot ) + { + iWaiter.Close(); + iWaiter = null; + } + } + } + + private uint FixupAddress( uint aAddress ) + { + uint ret = aAddress - iRelocationAddress; + return ret; + } + #endregion + + #region From ITracer + public void Trace( string aMessage ) + { + iImage.Trace( aMessage ); + } + + public void Trace( string aFormat, params object[] aParams ) + { + iImage.Trace( aFormat, aParams ); + } + #endregion + + #region From DisposableObject + protected override void CleanupManagedResources() + { + try + { + base.CleanupManagedResources(); + } + finally + { + iImage.Remove( this ); + // + if ( iWaiter != null ) + { + iWaiter.Set(); + iWaiter.Close(); + iWaiter = null; + } + } + } + #endregion + + #region From System.Object + public override string ToString() + { + return FileName; + } + + public override int GetHashCode() + { + return FileName.GetHashCode(); + } + #endregion + + #region Data members + private readonly SIImage iImage; + private uint iRelocationAddress = 0; + private bool iDecompressionException = false; + private AutoResetEvent iWaiter = null; + private object iWaiterSyncRoot = new object(); + #endregion + } +}