crashanalysercmd/PerfToolsSharedLibraries/Engine/SymbianImageLib/ROM/Content/SIContentROM.cs
author Matti Laitinen <matti.t.laitinen@nokia.com>
Thu, 11 Feb 2010 15:50:58 +0200
changeset 0 818e61de6cd1
permissions -rw-r--r--
Add initial version of Crash Analyser cmdline under EPL

/*
* 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 SymbianUtils;
using SymbianUtils.Tracer;
using SymbianUtils.Streams;
using SymbianStructuresLib.Uids;
using SymbianStructuresLib.Compression.Common;
using SymbianImageLib.Common.Content;
using SymbianImageLib.Common.Image;
using SymbianImageLib.Common.Header;
using SymbianImageLib.Common.Streams;
using SymbianImageLib.Common.Factory;
using SymbianImageLib.ROM.Image;
using SymbianImageLib.ROM.Header;
using SymbianImageLib.ROM.Structures;

namespace SymbianImageLib.ROM.Content
{
    internal class SIContentROM : SIContent
    {
        #region Constructors
        public SIContentROM( SIROM aImage )
            : base( aImage )
        {
            SIHeaderROM header = (SIHeaderROM) aImage.Header;
            base.RelocationAddress = header.RomBaseAddress;
        }
        #endregion

        #region From SymbianImageContentFile
        public override TSymbianCompressionType CompressionType
        {
            get
            {
                // Compression type comes from overall image header
                TSymbianCompressionType ret = base.ImageHeader.CompressionType;
                return ret;
            }
        }

        public override bool IsRelocationSupported
        {
            get { return false; }
        }

        public override string FileName
        {
            get { return Image.Name; }
        }

        public override uint FileSize
        {
            get { return (uint) base.Image.Stream.Length; }
        }

        public override uint ContentSize
        {
            get
            {
                // This is not 100% accurate, but hopefully good enough...
                uint size = (uint) base.ImageStream.Length;
                return size;
            }
        }

        public override byte[] GetAllData()
        {
            // The image ownes a memory stream (if the image has been decompressed)
            byte[] ret = new byte[ 0 ];
            //
            if ( base.ImageStream is SIMemoryStream )
            {
                SIMemoryStream memStream = (SIMemoryStream) base.ImageStream;
                ret = memStream.Data;
            }
            //
            return ret;
        }

        protected override uint DoProvideDataUInt32( uint aTranslatedAddress )
        {
            using ( SymbianStreamReaderLE reader = Image.Stream.CreateReader( SymbianStreamReaderLE.TCloseOperation.ENone ) )
            {
                reader.Seek( aTranslatedAddress );
                uint ret = reader.ReadUInt32();
                return ret;
            }
        }

        protected override ushort DoProvideDataUInt16( uint aTranslatedAddress )
        {
            using ( SymbianStreamReaderLE reader = Image.Stream.CreateReader( SymbianStreamReaderLE.TCloseOperation.ENone ) )
            {
                reader.Seek( aTranslatedAddress );
                ushort ret = reader.ReadUInt16();
                return ret;
            }
        }

        protected override void DoDecompress()
        {
            base.Trace( "[SymbianImageContentFileROM] DoDecompress() - START - compression type: {0}", CompressionType );
            //
            switch ( CompressionType )
            {
            case TSymbianCompressionType.ENone:
                base.Trace( "[SymbianImageContentFileROM] DoDecompress() - not compressed" );
                break;
            case TSymbianCompressionType.EBytePair:
                base.Trace( "[SymbianImageContentFileROM] DoDecompress() - byte pair" );
                DoDecompressBytePair();
                break;
            default:
            case TSymbianCompressionType.EDeflate:
                base.Trace( "[SymbianImageContentFileROM] DoDecompress() - unsuporrted compression type" );
                throw new NotSupportedException();
            }
            //
            base.Trace( "[SymbianImageROM] DoDecompress() - END" );
        }

        protected override bool GetIsContentPrepared()
        {
            return iContentIsPrepared;
        }
        #endregion

        #region Properties
        public new SIHeaderROM ImageHeader
        {
            get
            {
                SIHeaderROM header = (SIHeaderROM) base.ImageHeader;
                return header;
            }
        }
        #endregion

        #region Internal methods
        private void DoDecompressBytePair()
        {
            if ( iContentIsPrepared == false )
            {
                SIHeaderROM imageHeader = ImageHeader;
                base.Trace( "[SymbianImageROM] DoDecompressBytePair() - START - header uncompressed rom size: {0}", imageHeader.UncompressedRomSize );

                // Create new buffer and copy over rom image header
                SIMemoryStream resultantDataStream = new SIMemoryStream( imageHeader.UncompressedRomSize );

                int numPages = imageHeader.NumberOfPages;
                uint pageTableOffset = imageHeader.RomPageIndexOffset;
                uint romDataOffset = imageHeader.HeaderSizeLoader;
                base.Trace( "[SymbianImageROM] DoDecompressBytePair() - numPages: {0}, pageTableOffset: {1}, romDataOffset: {2}", numPages, pageTableOffset, romDataOffset );
                //
                SymbianDecompressor decompressor = SymbianDecompressor.NewByType( TSymbianCompressionType.EBytePair );
                //
                List<SRomPageInfo> pages = new List<SRomPageInfo>( numPages + 1 );
                for ( int i = 0; i < numPages; i++ )
                {
                    // Read a page table entry
                    long pageOffsetWithinFile = pageTableOffset + ( i * SRomPageInfo.Size );

                    //base.Trace( "[SymbianImageROM] DoDecompressBytePair() - page[{0:d5}] - pageOffsetWithinFile: {1}", i, pageOffsetWithinFile );
                    base.ImageStream.Seek( pageOffsetWithinFile, SeekOrigin.Begin );
                    SRomPageInfo pageInfo = SRomPageInfo.New( (Stream) base.ImageStream, romDataOffset );

                    // Process the entry based upon the compression type
                    //base.Trace( "[SymbianImageROM] DoDecompressBytePair() - page[{0:d5}] - pageInfo.DataSize: {1}, pageInfo.DataStart: {2}, pageInfo.CompressionType: {3}", i, pageInfo.DataSize, pageInfo.DataStart, pageInfo.CompressionType );
                    base.ImageStream.Seek( pageInfo.DataStart, SeekOrigin.Begin );

                    if ( pageInfo.CompressionType == SRomPageInfo.TSymbianCompressionType.ENoCompression )
                    {
                        // Read data - no decompression needed
                        //base.Trace( "[SymbianImageROM] DoDecompressBytePair() - page[{0:d5}] - PAGE NOT COMPRESSED", i );
                        resultantDataStream.Write( base.ImageStream, (int) pageInfo.DataSize );
                    }
                    else if ( pageInfo.CompressionType == SRomPageInfo.TSymbianCompressionType.EBytePair )
                    {
                        //base.Trace( "[SymbianImageROM] DoDecompressBytePair() - page[{0:d5}] - BYTE PAIR PAGE", i );

                        // Read data - need to decompress it
                        byte[] compressedData = new byte[ pageInfo.DataSize ];
                        base.ImageStream.Read( compressedData, 0, compressedData.Length );

                        // Make destination buffer - which is a page big
                        byte[] uncompressedData = new byte[ SRomPageInfo.KPageSize ];

                        // Decompress to buffer - we're handling the page management, so we want raw decompression
                        int error = decompressor.DecompressRaw( compressedData, uncompressedData );

                        // Save it
                        if ( error < 0 )
                        {
                            base.Trace( "[SymbianImageROM] DoDecompressBytePair() - page[{0:d5}] - Exception - bytepair decompression error", i );
                            throw new Exception( "BytePair decompression error: " + error.ToString() );
                        }
                        else if ( error != SRomPageInfo.KPageSize )
                        {
                            base.Trace( "[SymbianImageROM] DoDecompressBytePair() - page[{0:d5}] - Exception - bytepair underflow error", i );
                            throw new Exception( "Decompressor underflow - only created " + error.ToString() + " bytes" );
                        }
                        else
                        {
                            resultantDataStream.Write( uncompressedData );
                        }
                    }
                    else
                    {
                        base.Trace( "[SymbianImageROM] DoDecompressBytePair() - page[{0:d5}] - UNSUPPORTED COMPRESSION TYPE - Exception!", i );
                        throw new NotSupportedException( "Unsupported page compression type" );
                    }

                    // Report progress
                    base.ReportDecompressionEvent( TDecompressionEvent.EEventDecompressionProgress, ( (float) i / (float) numPages ) * 100 );
                }

                // Now we can replace the base class stream (which is just the raw compressed file data) with the new uncompressed version
                base.ImageStream = resultantDataStream;
                iContentIsPrepared = true;

                base.Trace( "[SymbianImageROM] DoDecompressBytePair() - END" );
            }
        }
        #endregion

        #region Data members
        private bool iContentIsPrepared = false;
        #endregion
    }
}