crashanalysercmd/UI/CrashServer/Engine/CACmdLineEngine.cs
changeset 0 818e61de6cd1
child 2 0c91f0baec58
equal deleted inserted replaced
-1:000000000000 0:818e61de6cd1
       
     1 /*
       
     2 * Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     3 * All rights reserved.
       
     4 * This component and the accompanying materials are made available
       
     5 * under the terms of "Eclipse Public License v1.0"
       
     6 * which accompanies this distribution, and is available
       
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 *
       
     9 * Initial Contributors:
       
    10 * Nokia Corporation - initial contribution.
       
    11 *
       
    12 * Contributors:
       
    13 *
       
    14 * Description: 
       
    15 *
       
    16 */
       
    17 using System;
       
    18 using System.Text;
       
    19 using System.IO;
       
    20 using System.Xml;
       
    21 using System.Collections.Generic;
       
    22 using CrashItemLib.Crash;
       
    23 using CrashItemLib.Crash.Container;
       
    24 using CrashItemLib.Crash.Source;
       
    25 using CrashItemLib.Crash.Processes;
       
    26 using CrashItemLib.Crash.Messages;
       
    27 using CrashItemLib.Crash.Summarisable;
       
    28 using CrashItemLib.Sink;
       
    29 using CrashItemLib.Engine;
       
    30 using CrashItemLib.Engine.Sources;
       
    31 using CrashItemLib.Engine.Interfaces;
       
    32 using CrashItemLib.PluginAPI;
       
    33 using SymbianUtils.FileSystem.Utilities;
       
    34 using SymbianXmlInputLib.Parser;
       
    35 using SymbianXmlInputLib.Parser.Nodes;
       
    36 using SymbianXmlInputLib.Elements;
       
    37 using SymbianXmlInputLib.Elements.Types.Category;
       
    38 using SymbianXmlInputLib.Elements.Types.FileSystem;
       
    39 using SymbianXmlInputLib.Elements.Types.Command;
       
    40 using SymbianDebugLib;
       
    41 using SymbianDebugLib.Engine;
       
    42 using SymbianDebugLib.Entity;
       
    43 using SymbianUtils;
       
    44 using SymbianUtils.Tracer;
       
    45 using CrashItemLib.Crash.InfoSW;
       
    46 
       
    47 namespace CrashAnalyserServerExe.Engine
       
    48 {
       
    49     internal class CACmdLineEngine : DisposableObject, ITracer, ICIEngineUI
       
    50 	{
       
    51 		#region Constructors
       
    52         public CACmdLineEngine( DbgEngine aDebugEngine )
       
    53 		{
       
    54             iDebugEngine = aDebugEngine;
       
    55             iInputs = new CACmdLineInputParameters( aDebugEngine );
       
    56             iCrashItemEngine = new CIEngine( aDebugEngine, this as ICIEngineUI );
       
    57 		}
       
    58 		#endregion
       
    59 
       
    60         #region API
       
    61         public int RunCommandLineOperations()
       
    62         {
       
    63             Trace( "[CA Cmd] START " );
       
    64             Trace( string.Empty );
       
    65             Trace( "[CA Cmd] command line: " + System.Environment.CommandLine );
       
    66             Trace( "[CA Cmd] command wd:   " + System.Environment.CurrentDirectory );
       
    67             Trace( "[CA Cmd] proc count:   " + System.Environment.ProcessorCount );
       
    68             Trace( "[CA Cmd] sysdir:       " + System.Environment.SystemDirectory );
       
    69             Trace( "[CA Cmd] version:      " + System.Environment.Version.ToString() );
       
    70             Trace( string.Empty );
       
    71 
       
    72             int error = CACmdLineException.KErrNone;
       
    73                         
       
    74             //
       
    75             try
       
    76             {
       
    77                 if (!iInputs.ParseCommandLine())
       
    78                 {
       
    79                     throw new CACmdLineException("Error while parsing command line", CACmdLineException.KErrCommandLineError);
       
    80                 }
       
    81                 
       
    82                 // We expect to see an "-input" parameter
       
    83                 iReportProgress = CheckForProgressParameter();
       
    84 
       
    85                 // Switch off UI output at the debug engine level
       
    86                 iDebugEngine.UiMode = TDbgUiMode.EUiDisabled;
       
    87 
       
    88                 // Next, attempt to prime the crash engine with every source we
       
    89                 // identified from the input specification. The goal is to
       
    90                 // create all the needed Crash Item Source objects for each input file.
       
    91                 // Any inputs which we don't support will not have an associated source and
       
    92                 // will be flagged accordingly within the CACmdLineFileSource object.
       
    93                 TryToPrimeSources();
       
    94 
       
    95                 // Next, prime the debug engine will all the debug meta-data inputs.
       
    96                 // Again, individual error messages will be associated with each meta-data
       
    97                 // input.
       
    98                 TryToPrimeDbgEngine();
       
    99 
       
   100                 // Next, we invoke the crash engine to process all the crash item sources we
       
   101                 // created during the prime step. Exceptions are caught and associated 
       
   102                 // messages & diagnostics are created at the input-file level.
       
   103                 TryToIdentifyCrashes();
       
   104 
       
   105                 // Next, we start the output phase. Any 'valid' crash containers are serialized
       
   106                 // to xml. Any input files which could not be processed have 'dummy' containers
       
   107                 // created for them, and these are also serialised to 'failed' CI files.
       
   108                 // If the CI Sink plugin is unavailable, then we cannot create any CI output.
       
   109                 // In this situation, we throw an exception which is caught below.
       
   110                 TryToCreateOutput();
       
   111             }
       
   112             catch ( CACmdLineException cmdLineException )
       
   113             {
       
   114                 error = cmdLineException.ErrorCode;
       
   115                 //
       
   116                 Trace( "[CA Cmd] " + cmdLineException.Message + " " + cmdLineException.StackTrace );
       
   117             }
       
   118             catch ( Exception generalException )
       
   119             {
       
   120                 error = CACmdLineException.KErrGeneral;
       
   121                 //
       
   122                 Trace( "[CA Cmd] " + generalException.Message + " " + generalException.StackTrace );
       
   123             }
       
   124             
       
   125             Trace( "[CA Cmd] - operation complete: " + error );
       
   126             return error;
       
   127         }
       
   128         #endregion
       
   129 
       
   130 		#region Properties
       
   131         public string CommandLineArguments
       
   132         {
       
   133             get { return Environment.CommandLine; }
       
   134         }
       
   135  
       
   136         public CIEngine CrashItemEngine
       
   137         {
       
   138             get { return iCrashItemEngine; }
       
   139         }
       
   140         #endregion
       
   141 
       
   142         #region Event handlers
       
   143         private void DbgEngine_EntityPrimingStarted( DbgEngine aEngine, DbgEntity aEntity, object aContext )
       
   144         {
       
   145             Trace( "[CA Cmd] Priming debug meta-data: " + aEntity.FullName );
       
   146 
       
   147             // Emit progress banner
       
   148             if ( iReportProgress )
       
   149             {
       
   150                 Print( "Reading debug meta-data..." );
       
   151             }
       
   152         }
       
   153 
       
   154         private void DbgEngine_EntityPrimingProgress( DbgEngine aEngine, DbgEntity aEntity, object aContext )
       
   155         {
       
   156             if ( aContext != null )
       
   157             {
       
   158                 if ( aContext.GetType() == typeof( int ) )
       
   159                 {
       
   160                     int value = (int) aContext;
       
   161                     Trace( "[CA Cmd] Priming debug meta-data progress: {0:d3}% {1}", value, aEntity.FullName );
       
   162 
       
   163                     // If reporting progress, then output something so the carbide extension is aware
       
   164                     // of what is going on in the background.
       
   165                     if ( iReportProgress )
       
   166                     {
       
   167                         string msg = string.Format( "{1:d3}%, {0}", aEntity.FullName, value );
       
   168                         Print( msg );
       
   169                     }
       
   170                 }
       
   171             }
       
   172         }
       
   173 
       
   174         private void DbgEngine_EntityPrimingComplete( DbgEngine aEngine, DbgEntity aEntity, object aContext )
       
   175         {
       
   176             Trace( "[CA Cmd] Primed debug meta-data: " + aEntity.FullName );
       
   177         }
       
   178 
       
   179         private void CrashItemEngine_SourceObserver( CIEngine.TSourceEvent aEvent, CIEngineSource aSource, object aParameter )
       
   180         {
       
   181             if ( iReportProgress )
       
   182             {
       
   183                 string msg = string.Empty;
       
   184                 //
       
   185                 switch ( aEvent )
       
   186                 {
       
   187                 case CIEngine.TSourceEvent.EEventSourceReady:
       
   188                     msg = string.Format( "Reading file: [{0}], progress: 100%", aSource.FileName );
       
   189                     break;
       
   190                 case CIEngine.TSourceEvent.EEventSourceProgress:
       
   191                     if ( aParameter != null && aParameter is int )
       
   192                     {
       
   193                         msg = string.Format( "Reading file: [{0}], progress: {1:d3}%", aSource.FileName, (int) aParameter );
       
   194                     }
       
   195                     break;
       
   196                 default:
       
   197                     break;
       
   198                 }
       
   199                 
       
   200                 // Output a message only if we have one
       
   201                 if ( string.IsNullOrEmpty( msg ) == false )
       
   202                 {
       
   203                     Print( msg );
       
   204                 }
       
   205             }
       
   206         }
       
   207         #endregion
       
   208 
       
   209         #region Internal constants
       
   210         private const string KCrashItemSinkName = "CRASH INFO FILE";
       
   211         private const string KParamProgress = "-PROGRESS";
       
   212         #endregion
       
   213 
       
   214         #region Internal methods
       
   215         private bool CheckForProgressParameter()
       
   216         {
       
   217             bool report = this.CommandLineArguments.Contains( KParamProgress );
       
   218             return report;
       
   219         }
       
   220 
       
   221         private CISink FindSink()
       
   222         {
       
   223             Trace( "[CA Cmd] FindSink() - START" );
       
   224             CISink ret = null;
       
   225             //
       
   226             CISinkManager sinkManager = iCrashItemEngine.SinkManager;
       
   227             foreach ( CISink sink in sinkManager )
       
   228             {
       
   229                 Trace( "[CA Cmd] FindSink() - found sink: " + sink.Name );
       
   230 
       
   231                 if ( sink.Name.ToUpper().Contains( KCrashItemSinkName ) )
       
   232                 {
       
   233                     ret = sink;
       
   234                     break;
       
   235                 }
       
   236             }
       
   237             //
       
   238             Trace( "[CA Cmd] FindSink() - END - ret: " + ret );
       
   239             return ret;
       
   240         }
       
   241 
       
   242         private void TryToPrimeSources()
       
   243         {
       
   244             Trace( "[CA Cmd] TryToPrimeSources() - START" );
       
   245             CrashItemEngine.ClearAll();
       
   246             
       
   247             // Prime engine with source files
       
   248             CACmdLineFSEntityList<CACmdLineFileSource> sourceFileNames = iInputs.SourceFiles;
       
   249             int progress = -1;
       
   250             int count = sourceFileNames.Count;
       
   251 
       
   252             // Emit progress banner
       
   253             if ( iReportProgress )
       
   254             {
       
   255                 Print( "Locating crash files..." );
       
   256             }
       
   257 
       
   258             for ( int i = 0; i < count; i++ )
       
   259             {
       
   260                 CACmdLineFileSource file = sourceFileNames[ i ];
       
   261                 //
       
   262                 try
       
   263                 {
       
   264                     // We prime each file individually. If an exception is thrown then we
       
   265                     // record an appropriate error in the associated file object.
       
   266                     Trace( "[CA Cmd] TryToPrimeSources() - priming: " + file );
       
   267 
       
   268                     bool primeSuccess = CrashItemEngine.Prime( file );
       
   269 
       
   270                     // Report progress as we work through the sources
       
   271                     if ( iReportProgress )
       
   272                     {
       
   273                         float newProgress = ( ( (float) i + 1 ) / (float) count ) * 100.0f;
       
   274                         if ( (int) newProgress != progress || i == count - 1 )
       
   275                         {
       
   276                             progress = (int) newProgress;
       
   277                             Print( string.Format( "{0:d3}%", progress ) );
       
   278                         }
       
   279                     }
       
   280 
       
   281                     Trace( "[CA Cmd] TryToPrimeSources() - primed result: " + primeSuccess );
       
   282                 }
       
   283                 catch ( Exception sourcePrimerException )
       
   284                 {
       
   285                     file.AddError( "Error Identifying Source Type", "There was an error when attempting to identify the source file type. The file could not be processed." );
       
   286                     file.AddDiagnostic( "Crash Primer Exception Message", sourcePrimerException.Message );
       
   287                     file.AddDiagnostic( "Crash Primer Exception Stack", sourcePrimerException.StackTrace );
       
   288                 }
       
   289             }
       
   290 
       
   291             AssociateInputFilesWithCrashItemSources();
       
   292             Trace( "[CA Cmd] TryToPrimeSources() - END" );
       
   293         }
       
   294 
       
   295         private void TryToPrimeDbgEngine()
       
   296         {
       
   297             DbgEngine debugEngine = iDebugEngine;
       
   298             //
       
   299             Exception primerException = null;
       
   300             CACmdLineFSEntityList<CACmdLineFSEntity> metaDataFiles = iInputs.MetaDataFiles;
       
   301             //
       
   302             try
       
   303             {
       
   304                 debugEngine.Clear();
       
   305 
       
   306                 foreach ( CACmdLineFSEntity entry in metaDataFiles )
       
   307                 {
       
   308                     Trace( "[CA Cmd] Seeding debug meta engine with entry: " + entry.Name );
       
   309                     DbgEntity entity = debugEngine.Add( entry.Name );
       
   310                     if ( entity != null )
       
   311                     {
       
   312                         Trace( "[CA Cmd] Entry type detected as: [" + entity.CategoryName + "]" );
       
   313                         entity.Tag = entry;
       
   314                     }
       
   315                     else
       
   316                     {
       
   317                         Trace( "[CA Cmd] Entry not handled: " + entry.Name );
       
   318                         entry.AddError( "Meta-Data File Not Supported", "The file \'" + entry.Name + "\' is of unknown origin." );
       
   319                     }
       
   320                 }
       
   321 
       
   322                 // Listen to prime events
       
   323                 try
       
   324                 {
       
   325                     Trace( "[CA Cmd] Starting prime operation... " );
       
   326                     debugEngine.EntityPrimingStarted += new DbgEngine.EventHandler( DbgEngine_EntityPrimingStarted );
       
   327                     debugEngine.EntityPrimingProgress += new DbgEngine.EventHandler( DbgEngine_EntityPrimingProgress );
       
   328                     debugEngine.EntityPrimingComplete += new DbgEngine.EventHandler( DbgEngine_EntityPrimingComplete );
       
   329                     debugEngine.Prime( TSynchronicity.ESynchronous );
       
   330                     Trace( "[CA Cmd] Debug meta data priming completed successfully." );
       
   331                 }
       
   332                 finally
       
   333                 {
       
   334                     debugEngine.EntityPrimingStarted -= new DbgEngine.EventHandler( DbgEngine_EntityPrimingStarted );
       
   335                     debugEngine.EntityPrimingProgress -= new DbgEngine.EventHandler( DbgEngine_EntityPrimingProgress );
       
   336                     debugEngine.EntityPrimingComplete -= new DbgEngine.EventHandler( DbgEngine_EntityPrimingComplete );
       
   337                 }
       
   338             }
       
   339             catch ( Exception exception )
       
   340             {
       
   341                 Trace( "[CA Cmd] Debug meta data priming exception: " + exception.Message + ", " + exception.StackTrace );
       
   342                 primerException = exception;
       
   343             }
       
   344 
       
   345             // Go through each debug entity and check it for errors. Add diagnostics
       
   346             // and error messages where appropriate.
       
   347             foreach ( DbgEntity entity in debugEngine )
       
   348             {
       
   349                 string name = entity.FullName;
       
   350                 //
       
   351                 CACmdLineFSEntity file = metaDataFiles[ name ];
       
   352                 file.Clear();
       
   353                 //
       
   354                 if ( entity.PrimerResult.PrimedOkay )
       
   355                 {
       
   356                     if ( !entity.Exists )
       
   357                     {
       
   358                         file.AddError( "Meta-Data File Missing", string.Format( "The file \'{0}\' could not be found.", file.Name ) );
       
   359                     }
       
   360                     else if ( entity.IsUnsupported )
       
   361                     {
       
   362                         file.AddError( "Meta-Data File Not Supported", string.Format( "The file \'{0}\' is of unknown origin.", file.Name ) );
       
   363                     }
       
   364                 }
       
   365                 else
       
   366                 {
       
   367                     // Add error
       
   368                     file.AddError( "Meta-Data Read Error", entity.PrimerResult.PrimeErrorMessage );
       
   369 
       
   370                     // And diagnostic information
       
   371                     Exception exception = entity.PrimerResult.PrimeException != null ? entity.PrimerResult.PrimeException : primerException;
       
   372                     if ( exception != null )
       
   373                     {
       
   374                         file.AddDiagnostic( "Meta-Data Exception Message", entity.PrimerResult.PrimeException.Message );
       
   375                         file.AddDiagnostic( "Meta-Data Exception Stack", entity.PrimerResult.PrimeException.StackTrace );
       
   376                     }
       
   377                     else
       
   378                     {
       
   379                         file.AddDiagnostic( "Meta-Data Unknown Failure", "No exception occurred at the primer or entity level?" );
       
   380                     }
       
   381                 }
       
   382             }
       
   383         }
       
   384 
       
   385         private void TryToIdentifyCrashes()
       
   386         {
       
   387             Exception crashEngineException = null;
       
   388             //
       
   389             try
       
   390             {
       
   391                 iCrashItemEngine.SourceObservers += new CIEngine.CIEngineSourceObserver( CrashItemEngine_SourceObserver );
       
   392                 iCrashItemEngine.IdentifyCrashes( TSynchronicity.ESynchronous );
       
   393             }
       
   394             catch ( Exception exception )
       
   395             {
       
   396                 crashEngineException = exception;
       
   397             }
       
   398             finally
       
   399             {
       
   400                 iCrashItemEngine.SourceObservers -= new CIEngine.CIEngineSourceObserver( CrashItemEngine_SourceObserver );
       
   401             }
       
   402 
       
   403             // Check each source in the engine and create messages based upon it's
       
   404             // state at the end of processing.
       
   405             foreach ( CACmdLineFileSource file in iInputs.SourceFiles )
       
   406             {
       
   407                 if ( file.Source != null )
       
   408                 {
       
   409                     CIEngineSource source = file.Source;
       
   410                     switch ( source.State )
       
   411                     {
       
   412                     case CIEngineSource.TState.EStateReady:
       
   413                         // Success case - the source resulted in the creation of at least one container
       
   414                         file.AddDiagnostic( "Source Read Successfully", string.Format( "{0} crash container(s) created", source.ContainerCount ) );
       
   415                         break;
       
   416                     case CIEngineSource.TState.EStateReadyNoItems:
       
   417                         file.AddWarning( "Source File Contains No Crashes", "The input data was read successfully but contains no crash information." );
       
   418                         break;
       
   419                     case CIEngineSource.TState.EStateReadyCorrupt:
       
   420                         file.AddError( "Source File is Corrupt", "The input data is invalid or corrupt." );
       
   421                         break;
       
   422                     case CIEngineSource.TState.EStateUninitialised:
       
   423                         file.AddError( "Source File not Read", "The input data was never read." );
       
   424                         file.AddDiagnostic( "Source State Invalid", "Source is still in unitialised state, even though reading is complete?" );
       
   425                         break;
       
   426                     case CIEngineSource.TState.EStateProcessing:
       
   427                         file.AddDiagnostic( "Source State Invalid", "Source is still in processing state, even though reading is complete?" );
       
   428                         break;
       
   429                     default:
       
   430                         break;
       
   431                     }
       
   432                 }
       
   433                 else
       
   434                 {
       
   435                     file.AddError( "File is Not Supported", "There file type is not recognized and was not processed." );
       
   436                 }
       
   437 
       
   438                 // Add in details of any exception
       
   439                 if ( crashEngineException != null )
       
   440                 {
       
   441                     file.AddDiagnostic( "Crash Identification Exception Message", crashEngineException.Message );
       
   442                     file.AddDiagnostic( "Crash Identification Exception Stack", crashEngineException.StackTrace );
       
   443                 }
       
   444             }
       
   445         }
       
   446 
       
   447         private void TryToCreateOutput()
       
   448         {
       
   449             CACmdLineFSEntityList<CACmdLineFileSource> inputFiles = iInputs.SourceFiles;
       
   450             //
       
   451             CISink sink = FindSink();
       
   452             if ( sink == null )
       
   453             {
       
   454                 throw new CACmdLineException( "CI Output Plugin Not Available", CACmdLineException.KErrSinkNotAvailable );
       
   455             }
       
   456   
       
   457             CACmdLineFSEntityList<CACmdLineFileSource> sourceFileNames = iInputs.SourceFiles;
       
   458             int progress = -1;
       
   459             int count = sourceFileNames.Count;
       
   460 
       
   461             // Emit progress banner
       
   462             if ( iReportProgress )
       
   463             {
       
   464                 Print( "Creating CI content..." );
       
   465             }
       
   466             
       
   467             for ( int i = 0; i < count; i++ )
       
   468             {
       
   469                 CACmdLineFileSource file = sourceFileNames[ i ];
       
   470 
       
   471                 System.Console.WriteLine("Starting to process file " +file.Name);
       
   472 
       
   473                 // If the file has a corresponding source then we know that crash item recognised it.
       
   474                 // Otherwise, we skip it.
       
   475                 if ( file.Source != null )
       
   476                 {
       
   477                     // We copy and remove all the file-level messages. These will be added to the container
       
   478                     // (where appropriate) or then to an output entry otherwise.
       
   479                     CACmdLineMessage[] fileMessages = file.ToArray();
       
   480                     file.Clear();
       
   481 
       
   482                     // At this point, the input file is guaranteed to have an associated container. In
       
   483                     // the current mobile crash file format, there will be a 1:1 mapping, i.e. each file
       
   484                     // will contain a single crash report ("container") and therefore if symbols were
       
   485                     // found for just a single container (within the file) then it's good enough to treat
       
   486                     // the file as archivable.
       
   487                     foreach ( CIContainer container in file.Containers )
       
   488                     {
       
   489                         // Firstly, add any meta-data errors/messages/warnings to this container
       
   490                         // as crash item message entries
       
   491                         AddMetaDataMessagesToContainer( container );
       
   492 
       
   493                         SetArchiveFileName(file.Name, container, sink);
       
   494 
       
   495                         foreach (CIMessage message in container.Messages)
       
   496                         {
       
   497                             if (message.Type == CrashItemLib.Crash.Messages.CIMessage.TType.ETypeError)
       
   498                             {
       
   499                                 container.Status = CIContainer.TStatus.EStatusErrorContainer;
       
   500                             }
       
   501                         }
       
   502                         // Now we can try to serialize the container to CI. This method will
       
   503                         // not throw an exception.
       
   504                         //
       
   505                         // If the operation succeeds, then the input file will have an associated
       
   506                         // container object (and associated xml output file name) and we need not
       
   507                         // do anymore.
       
   508                         //
       
   509                         // If it fails, then the input file will not be assigned the container
       
   510                         // object and therefore, later on, we'll invoke the CI Sink directly to 
       
   511                         // create a stub 'FAILED' CI output file.
       
   512                         //
       
   513                         // NB: If Symbols were not available for the specified container, then
       
   514                         // we don't create a CI file but instead callback to a helper that
       
   515                         // will move the file to another temporary location for later repeat
       
   516                         // processing
       
   517                         bool hasSymbols = ContainsSymbols( container );
       
   518                         
       
   519                         if (container.Status == CIContainer.TStatus.EStatusErrorContainer) //normally don't output containers with errors
       
   520                         {
       
   521                             file.State = CACmdLineFileSource.TState.EStateUninitialized;
       
   522                             if (iInputs.DecodeWithoutSymbols) //with force mode, output no matter what
       
   523                             {
       
   524                                 TryToCreateOutput(sink, container, file, fileMessages);
       
   525                             }
       
   526                         }
       
   527                         else if (hasSymbols || IsSymbollessMobileCrash( container ))
       
   528                         {                            
       
   529                             file.State = CACmdLineFileSource.TState.EStateProcessedAndReadyToBeArchived;
       
   530                             TryToCreateOutput(sink, container, file, fileMessages);
       
   531                         }
       
   532                         else if (IsSymbollessMobileCrash(container)) //Crash api and registration files do not need symbols
       
   533                         {
       
   534                             
       
   535                             file.State = CACmdLineFileSource.TState.EStateProcessedAndReadyToBeArchived;
       
   536                             TryToCreateOutput(sink, container, file, fileMessages);
       
   537                         }
       
   538                         else 
       
   539                         {                            
       
   540                             file.State = CACmdLineFileSource.TState.EStateSkippedDueToMissingSymbols;
       
   541                             if (iInputs.DecodeWithoutSymbols) //with force mode, output no matter what
       
   542                             {
       
   543                                 //remove this to prevent .corrupt_ci creation!
       
   544                                 TryToCreateOutput(sink, container, file, fileMessages);
       
   545                             }
       
   546                         }
       
   547                     }
       
   548                 }
       
   549                 else
       
   550                 {
       
   551                     file.State = CACmdLineFileSource.TState.EStateSkippedDueToNotBeingRecognized;
       
   552                 }
       
   553 
       
   554                 // Move file to final location
       
   555                 MoveProcessedFile( file );
       
   556 
       
   557                 // Report progress as we work through the sources
       
   558                 if ( iReportProgress )
       
   559                 {
       
   560                     float newProgress = ( ( (float) i + 1 ) / (float) count ) * 100.0f;
       
   561                     if ( (int) newProgress != progress || i == count - 1 )
       
   562                     {
       
   563                         progress = (int) newProgress;
       
   564                         Print( string.Format( "{0:d3}%", progress ) );
       
   565                     }
       
   566                 }
       
   567             }
       
   568         }
       
   569 
       
   570        
       
   571         private void SetArchiveFileName(string aFileFullPath, CIContainer aContainer, CISink sink)
       
   572         {
       
   573             string fileName = Path.GetFileName(aFileFullPath);
       
   574 
       
   575             //add romid to filename if not already there
       
   576             CIInfoSW info = (CIInfoSW) aContainer.ChildByType( typeof( CIInfoSW ) );
       
   577             if (info != null)
       
   578             {
       
   579                 //RomID
       
   580                 if (info.ImageCheckSum != 0)
       
   581                 {
       
   582                     string romid = info.ImageCheckSum.ToString("x8");
       
   583 
       
   584                     if (fileName.Length < 8 || fileName.Substring(0, 8) != romid)
       
   585                     {
       
   586                         fileName = romid + "_" + fileName;
       
   587                         
       
   588                     }
       
   589                 }
       
   590             }
       
   591             
       
   592             
       
   593             string basename = Path.GetFileNameWithoutExtension(fileName);
       
   594             string extension = Path.GetExtension(aFileFullPath);
       
   595             
       
   596             string archiveNamePath = Path.Combine(iInputs.ArchivePath, fileName); //Path.GetFileName(iInputs.ArchivePath));
       
   597             int counter = 1;               
       
   598             while (File.Exists(archiveNamePath))
       
   599             {
       
   600                 archiveNamePath = Path.Combine(iInputs.ArchivePath, basename + "_" + counter.ToString() + extension);
       
   601                 counter++;
       
   602             }
       
   603 
       
   604             iInputs.SinkParameters.OperationData1 = (Object)archiveNamePath;
       
   605             iBinFileArchivePathName = archiveNamePath;
       
   606            
       
   607         }
       
   608 
       
   609        
       
   610         private void TryToCreateOutput( CISink aXmlSink, CIContainer aContainer, CACmdLineFileSource aFile, CACmdLineMessage[] aMessagesToAdd )
       
   611         {
       
   612             Trace( "[CA Cmd] TryToCreateOutput() - START - container source: {0}", aContainer.Source.MasterFileName );
       
   613 
       
   614             // By the time we are outputting a container, there should no longer be any messages
       
   615             // associated with the file.
       
   616             System.Diagnostics.Debug.Assert( aFile.Count == 0 );
       
   617 
       
   618             // Check whether the file contained any errors or 
       
   619             // messages of it own.
       
   620             if ( aMessagesToAdd.Length > 0 )
       
   621             {
       
   622                 // Copy warnings, messages and errors into crash item container.
       
   623                 // Diagnostic messages are not copied.
       
   624                 CACmdLineFSEntity.CopyMessagesToContainer( aMessagesToAdd, aContainer );
       
   625             }
       
   626 
       
   627             // This is where we will record the output attempt
       
   628             CACmdLineFileSource.OutputEntry outputEntry = null;
       
   629             //
       
   630             try
       
   631             {
       
   632                 // Finish preparing the sink parameters
       
   633                 CISinkSerializationParameters sinkParams = iInputs.SinkParameters;
       
   634                 sinkParams.Container = aContainer;
       
   635 
       
   636                 // Perform serialization
       
   637                 Trace( "[CA Cmd] TryToCreateOutput() - serializing..." );
       
   638                 object output = aXmlSink.Serialize( sinkParams );
       
   639                 Trace( "[CA Cmd] TryToCreateOutput() - serialization returned: " + output );
       
   640 
       
   641                 if ( aFile != null )
       
   642                 {
       
   643                     // Create new output
       
   644                     string outputFileName = output is string ? (string) output : string.Empty;
       
   645 
       
   646                     // Save output file name
       
   647                     outputEntry = aFile.AddOutput( aContainer, outputFileName, TOutputStatus.ESuccess );
       
   648                 }
       
   649 
       
   650                 // Merge in any diagnostic messages that were left into the output entry.
       
   651                 // This ensure we output diagnostics in the final manifest data.
       
   652                 outputEntry.AddRange( aMessagesToAdd, CACmdLineMessage.TType.ETypeDiagnostic );
       
   653             }
       
   654             catch ( Exception outputException )
       
   655             {
       
   656                 Trace( "[CA Cmd] TryToCreateOutput() - outputException.Message:    " + outputException.Message );
       
   657                 Trace( "[CA Cmd] TryToCreateOutput() - outputException.StackTrace: " + outputException.StackTrace );
       
   658 
       
   659                 if ( aFile != null )
       
   660                 {
       
   661                     // Something went wrong with CI serialisation for the specified container.
       
   662                     outputEntry = aFile.AddOutput( aContainer, string.Empty, TOutputStatus.EFailed );
       
   663                     //
       
   664                     outputEntry.AddError( "Could not Create CI", "CI output could not be created" );
       
   665                     outputEntry.AddDiagnostic( "CI Sink Exception Message", outputException.Message );
       
   666                     outputEntry.AddDiagnostic( "CI Sink Exception Stack", outputException.StackTrace );
       
   667                     
       
   668                     // Since we didn't manage to sink the container to CI successfully, we must
       
   669                     // make sure we don't lose any associated messages from the original file. 
       
   670                     // Merge these into the output entry also.
       
   671                     outputEntry.AddRange( aMessagesToAdd );
       
   672                 }
       
   673             }
       
   674         }
       
   675 
       
   676         private void AssociateInputFilesWithCrashItemSources()
       
   677         {
       
   678             CACmdLineFSEntityList<CACmdLineFileSource> sourceFileNames = iInputs.SourceFiles;
       
   679 
       
   680             // Emit progress banner
       
   681             if ( iReportProgress )
       
   682             {
       
   683                 Print( "Categorizing files..." );
       
   684             }
       
   685             
       
   686             // Check each source in the engine and try to map it back onto an input source
       
   687             // file name. The goal is to identify input files which have no corresponding crash engine
       
   688             // source. These files are unsupported.
       
   689             CIEngineSourceCollection sources = iCrashItemEngine.Sources;
       
   690             int count = sources.Count;
       
   691             int progress = -1;
       
   692             for( int i=0; i<count; i++ )
       
   693             {
       
   694                 CIEngineSource source = sources[ i ];
       
   695                 string sourceFileName = source.FileName;
       
   696                 
       
   697                 // Try to match an input file with a given source object
       
   698                 CACmdLineFileSource inputFile = sourceFileNames[ sourceFileName ];
       
   699                 if ( inputFile != null )
       
   700                 {
       
   701                     inputFile.Source = source;
       
   702                 }
       
   703 
       
   704                 // Report progress as we work through the sources
       
   705                 if ( iReportProgress )
       
   706                 {
       
   707                     float newProgress = ( ( (float) i+1 ) / (float) count ) * 100.0f;
       
   708                     if ( (int) newProgress != progress || i == count - 1 )
       
   709                     {
       
   710                         progress = (int) newProgress;
       
   711                         Print( string.Format( "{0:d3}%", progress ) );
       
   712                     }
       
   713                 }
       
   714             }
       
   715         }
       
   716 
       
   717         private void AddMetaDataMessagesToContainer( CIContainer aContainer )
       
   718         {
       
   719             // All meta-data errors, warnings & messages are added as 
       
   720             // children of the container.
       
   721             CACmdLineFSEntityList<CACmdLineFSEntity> metaDataFiles = iInputs.MetaDataFiles;
       
   722             foreach ( CACmdLineFSEntity file in metaDataFiles )
       
   723             {
       
   724                 file.CopyMessagesToContainer( aContainer );
       
   725             }
       
   726         }
       
   727 
       
   728 
       
   729         private bool ContainsSymbols( CIContainer aContainer )
       
   730         {
       
   731             bool retval = false;
       
   732             if (aContainer.FileNames.Length > 1)
       
   733             {
       
   734                 retval = true;
       
   735             }
       
   736             return retval;
       
   737 
       
   738         }
       
   739 
       
   740         private bool IsSymbollessMobileCrash(CIContainer aContainer)
       
   741         {
       
   742             bool retval = false;
       
   743 
       
   744 
       
   745             foreach (CIMessage message in aContainer.Messages)
       
   746             {
       
   747                 if (message.Title == "MobileCrash content type")
       
   748                 {
       
   749                     if (message.Description.Trim() == "registration")
       
   750                     {
       
   751                         retval = true;
       
   752                     }
       
   753                     else if (message.Description.Trim() == "alive")
       
   754                     {
       
   755                         retval = true;
       
   756                     }
       
   757                     else if (message.Description.Trim() == "report")
       
   758                     {
       
   759                         retval = true;
       
   760                     }
       
   761                 }
       
   762             }
       
   763 
       
   764 
       
   765             return retval;
       
   766         }
       
   767 
       
   768 
       
   769         /*private bool ContainsSymbols( CIContainer aContainer )
       
   770         {
       
   771             // Symbols can be registered as the global level, or then per-process.
       
   772             bool ret = ( aContainer.SymbolDictionary.Count > 0 );            
       
   773             if ( ret == false )
       
   774             {
       
   775                 // Check at process level
       
   776                 CISummarisableEntityList summaries = aContainer.Summaries;
       
   777                 foreach ( CISummarisableEntity entity in summaries.ChildrenByType<CISummarisableEntity>() )
       
   778                 {
       
   779                     CIProcess process = entity.Process;
       
   780                     if ( process != null )
       
   781                     {
       
   782                         ret = ( process.SymbolDictionary.Count > 0 );
       
   783                         if ( ret == true )
       
   784                         {
       
   785                             break;
       
   786                         }
       
   787                     }
       
   788                 }
       
   789             }
       
   790             //
       
   791             return ret;
       
   792         }*/
       
   793 
       
   794         private void MoveProcessedFile( CACmdLineFileSource aFile )
       
   795         {
       
   796             string skippedTarget = Path.Combine(iInputs.SkippedPath, Path.GetFileName(iBinFileArchivePathName));
       
   797             string errorTarget = Path.Combine(iInputs.ErrorPath, Path.GetFileName(iBinFileArchivePathName));
       
   798 
       
   799             switch ( aFile.State )
       
   800             {
       
   801             case CACmdLineFileSource.TState.EStateProcessedAndReadyToBeArchived:
       
   802                 MoveFile(aFile, iBinFileArchivePathName);
       
   803                 break;
       
   804             case CACmdLineFileSource.TState.EStateSkippedDueToMissingSymbols:
       
   805                 MoveFile(aFile, skippedTarget);
       
   806                 break;
       
   807             case CACmdLineFileSource.TState.EStateSkippedDueToNotBeingRecognized:                
       
   808                 MoveFile(aFile, errorTarget);
       
   809                 break;
       
   810             default:               
       
   811                 MoveFile(aFile, errorTarget);
       
   812                 break;
       
   813             }
       
   814         }
       
   815 
       
   816         private void MoveFile(CACmdLineFileSource aFile, string aTargetPath)
       
   817         {
       
   818             string newName = aTargetPath;             
       
   819             
       
   820             //Name availability has already been checked before starting decoding for archive location
       
   821             //If file is going to skipped, its name may need changing
       
   822             if (File.Exists(newName))
       
   823             {
       
   824                 int counter = 1;
       
   825                 string original_name = newName;
       
   826                 while (File.Exists(newName))
       
   827                 {
       
   828                     string basepath = Path.GetDirectoryName(original_name);
       
   829                     string basename = Path.GetFileNameWithoutExtension(original_name);
       
   830                     string extension = Path.GetExtension(original_name);
       
   831                    
       
   832                     newName = Path.Combine(basepath, basename + "_" + counter.ToString() + extension);
       
   833                     counter++;
       
   834                 }
       
   835                 
       
   836             } 
       
   837 
       
   838             // Move the file.
       
   839             System.Console.WriteLine("Moving file " + aFile.Name + " to " + newName);
       
   840             if (!iInputs.TestWithoutMovingFiles)
       
   841             {
       
   842                 File.Move(aFile.Name, newName);
       
   843                 if (!File.Exists(newName))
       
   844                 {
       
   845                     System.Console.WriteLine("Error: unable to move file " +aFile.Name +" to " +newName );
       
   846                 }
       
   847             
       
   848             }
       
   849 
       
   850 
       
   851         }
       
   852 
       
   853         #endregion
       
   854 
       
   855         #region Output methods
       
   856         public void Print( string aMessage )
       
   857         {
       
   858             System.Console.WriteLine( aMessage );
       
   859         }
       
   860         #endregion
       
   861 
       
   862         #region From ITracer
       
   863         public void Trace( string aMessage )
       
   864         {
       
   865             System.Console.WriteLine("MANUAL TRACE:" +aMessage);
       
   866             iDebugEngine.Trace( aMessage );
       
   867         }
       
   868 
       
   869         public void Trace( string aFormat, params object[] aParams )
       
   870         {
       
   871             string msg = string.Format( aFormat, aParams );
       
   872             Trace( msg );
       
   873         }
       
   874         #endregion
       
   875 
       
   876         #region From ICIEngineUI
       
   877         void ICIEngineUI.CITrace( string aMessage )
       
   878         {
       
   879             Trace( aMessage );
       
   880         }
       
   881 
       
   882         void ICIEngineUI.CITrace( string aFormat, params object[] aParameters )
       
   883         {
       
   884             Trace( aFormat, aParameters );
       
   885         }
       
   886         #endregion
       
   887 
       
   888         #region From DisposableObject
       
   889         protected override void CleanupManagedResources()
       
   890         {
       
   891             try
       
   892             {
       
   893                 base.CleanupManagedResources();
       
   894             }
       
   895             finally
       
   896             {
       
   897                 iCrashItemEngine.Dispose();
       
   898             }
       
   899         }
       
   900         #endregion
       
   901 
       
   902         #region Data members
       
   903         private readonly DbgEngine iDebugEngine;
       
   904         private readonly CIEngine iCrashItemEngine;
       
   905         private readonly CACmdLineInputParameters iInputs;
       
   906         private bool iReportProgress = false;
       
   907         private string iBinFileArchivePathName = string.Empty;
       
   908         #endregion
       
   909     }
       
   910 }