|
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.Collections.Generic; |
|
21 using System.Reflection; |
|
22 using System.ComponentModel; |
|
23 using SymbianUtils; |
|
24 using SymbianDebugLib.Engine; |
|
25 using CrashItemLib.Crash; |
|
26 using CrashItemLib.Crash.Container; |
|
27 using CrashItemLib.PluginAPI; |
|
28 using CrashItemLib.Engine; |
|
29 using SymbianUtils.FileSystem.Utilities; |
|
30 |
|
31 namespace CrashItemLib.Sink |
|
32 { |
|
33 public class CISinkSerializationParameters : DisposableObject |
|
34 { |
|
35 #region Enumerations |
|
36 public enum TDetailLevel |
|
37 { |
|
38 [Description("Full")] |
|
39 EFull = 0, |
|
40 |
|
41 [Description( "Summary" )] |
|
42 ESummary |
|
43 } |
|
44 #endregion |
|
45 |
|
46 #region Constructors |
|
47 public CISinkSerializationParameters( Version aUIVersion, string aUICommandLineArguments ) |
|
48 { |
|
49 iUIVersion = aUIVersion; |
|
50 iUICommandLineArguments = aUICommandLineArguments; |
|
51 // |
|
52 string tempPath = FSUtilities.MakeTempPath(); |
|
53 OutputDirectory = new DirectoryInfo( tempPath ); |
|
54 // |
|
55 PrepareDefaultExtensions(); |
|
56 } |
|
57 |
|
58 public CISinkSerializationParameters( CIContainer aContainer, Version aUIVersion, string aUICommandLineArguments ) |
|
59 : this( aUIVersion, aUICommandLineArguments ) |
|
60 { |
|
61 iContainer = aContainer; |
|
62 } |
|
63 |
|
64 public CISinkSerializationParameters( CISinkSerializationParameters aCopy ) |
|
65 : this( aCopy.Container, aCopy.UIVersion, aCopy.UICommandLineArguments ) |
|
66 { |
|
67 iDetailLevel = aCopy.DetailLevel; |
|
68 // |
|
69 FileExtensionSuccess = aCopy.FileExtensionSuccess; |
|
70 FileExtensionFailed = aCopy.FileExtensionFailed; |
|
71 // |
|
72 if ( aCopy.iOutputMode == TOutputMode.EOutputToFile ) |
|
73 { |
|
74 OutputFile = aCopy.OutputFile; |
|
75 } |
|
76 else if ( aCopy.iOutputMode == TOutputMode.EOutputToDirectory ) |
|
77 { |
|
78 OutputDirectory = aCopy.OutputDirectory; |
|
79 } |
|
80 // |
|
81 iOperationData1 = aCopy.OperationData1; |
|
82 iOperationData2 = aCopy.OperationData2; |
|
83 iOperationData3 = aCopy.OperationData3; |
|
84 } |
|
85 #endregion |
|
86 |
|
87 #region API |
|
88 public Stream CreateFile( out string aFileName ) |
|
89 { |
|
90 return CreateFile( out aFileName, FileMode.Append ); |
|
91 } |
|
92 |
|
93 public Stream CreateFile( out string aFileName, FileMode aMode ) |
|
94 { |
|
95 System.Diagnostics.Debug.Assert( iContainer != null ); |
|
96 |
|
97 // First, prepare the output directory information that we will write to. |
|
98 string fileName = Container.Source.MasterFileName; |
|
99 string sourceFileName = Path.GetFileName( fileName ); |
|
100 string sourcePath = Path.GetDirectoryName( fileName ); |
|
101 // |
|
102 switch ( iOutputMode ) |
|
103 { |
|
104 case TOutputMode.EOutputToDirectory: |
|
105 // Use the OutputDirectory name, but combine with source file name |
|
106 fileName = Path.Combine( this.OutputDirectory.FullName, sourceFileName ); |
|
107 fileName = AppendFileExtension( fileName ); |
|
108 |
|
109 // Don't overwrite when writing to a specific directory. |
|
110 aMode = FileMode.CreateNew; |
|
111 break; |
|
112 default: |
|
113 case TOutputMode.EOutputToFile: |
|
114 // Use the specified OuputFile name. |
|
115 fileName = this.OutputFile.FullName; |
|
116 break; |
|
117 } |
|
118 |
|
119 // At this point we now have a fixed output path. |
|
120 // Ensure that it exists. |
|
121 DirectoryInfo outputDir = new DirectoryInfo( Path.GetDirectoryName( fileName ) ); |
|
122 outputDir.Create(); |
|
123 |
|
124 // Now try to make a unique file name if we are not appending. |
|
125 Stream ret = null; |
|
126 if ( aMode == FileMode.Append ) |
|
127 { |
|
128 // Just append to file |
|
129 ret = TryToCreateStream( fileName, aMode ); |
|
130 } |
|
131 else |
|
132 { |
|
133 // Update filename to just refer to the name and extension (no path) |
|
134 fileName = Path.GetFileName( fileName ); |
|
135 |
|
136 // Try to create a unique file |
|
137 for ( int counter = 0; counter < KMaxRetries; counter++ ) |
|
138 { |
|
139 // First iteration is a special case were we use input name |
|
140 // plus our standard extension |
|
141 string finalFileName = AppendFileExtension( fileName ); |
|
142 if ( counter > 0 ) |
|
143 { |
|
144 // Append a numerical value in order to create unique name |
|
145 finalFileName = string.Format( "{0} ({1:d3})", |
|
146 Path.GetFileNameWithoutExtension( fileName ), |
|
147 counter ); |
|
148 finalFileName = AppendFileExtension( finalFileName ); |
|
149 } |
|
150 |
|
151 string finalFullName = Path.Combine( outputDir.FullName, finalFileName ); |
|
152 |
|
153 // Attempt to create stream |
|
154 ret = TryToCreateStream( finalFullName, aMode ); |
|
155 if ( ret != null ) |
|
156 { |
|
157 fileName = finalFullName; |
|
158 break; |
|
159 } |
|
160 } |
|
161 } |
|
162 |
|
163 // |
|
164 if ( ret == null ) |
|
165 { |
|
166 throw new IOException( "Unable to create sink file" ); |
|
167 } |
|
168 else |
|
169 { |
|
170 // Ensure we inform caller of final output file name |
|
171 aFileName = fileName; |
|
172 } |
|
173 // |
|
174 return ret; |
|
175 } |
|
176 #endregion |
|
177 |
|
178 #region Framework API |
|
179 protected virtual void PrepareDefaultExtensions() |
|
180 { |
|
181 FileExtensionSuccess = string.Empty; |
|
182 FileExtensionFailed = string.Empty; |
|
183 } |
|
184 #endregion |
|
185 |
|
186 #region Properties |
|
187 public CIEngine Engine |
|
188 { |
|
189 get { return Container.Engine; } |
|
190 } |
|
191 |
|
192 public CIContainer Container |
|
193 { |
|
194 get { return iContainer; } |
|
195 set { iContainer = value; } |
|
196 } |
|
197 |
|
198 public TDetailLevel DetailLevel |
|
199 { |
|
200 get { return iDetailLevel; } |
|
201 set { iDetailLevel = value; } |
|
202 } |
|
203 |
|
204 public DirectoryInfo OutputDirectory |
|
205 { |
|
206 get |
|
207 { |
|
208 if ( iOutputMode != TOutputMode.EOutputToDirectory ) |
|
209 { |
|
210 throw new InvalidOperationException( "Output mode is invalid" ); |
|
211 } |
|
212 return iOutputDirectory; |
|
213 } |
|
214 set |
|
215 { |
|
216 iOutputDirectory = value; |
|
217 iOutputDirectory.Create(); |
|
218 // |
|
219 iOutputMode = TOutputMode.EOutputToDirectory; |
|
220 iOutputFile = null; |
|
221 } |
|
222 } |
|
223 |
|
224 public FileInfo OutputFile |
|
225 { |
|
226 get |
|
227 { |
|
228 if ( iOutputMode != TOutputMode.EOutputToFile ) |
|
229 { |
|
230 throw new InvalidOperationException( "Output mode is invalid" ); |
|
231 } |
|
232 return iOutputFile; |
|
233 } |
|
234 set |
|
235 { |
|
236 iOutputFile = value; |
|
237 // |
|
238 iOutputMode = TOutputMode.EOutputToFile; |
|
239 iOutputDirectory = null; |
|
240 } |
|
241 } |
|
242 |
|
243 public Version UIVersion |
|
244 { |
|
245 get { return iUIVersion; } |
|
246 } |
|
247 |
|
248 public string FileExtensionSuccess |
|
249 { |
|
250 get { return iFileExtensionSuccess; } |
|
251 set { iFileExtensionSuccess = value; } |
|
252 } |
|
253 |
|
254 public string FileExtensionFailed |
|
255 { |
|
256 get { return iFileExtensionFailed; } |
|
257 set { iFileExtensionFailed = value; } |
|
258 } |
|
259 |
|
260 public string UICommandLineArguments |
|
261 { |
|
262 get { return iUICommandLineArguments; } |
|
263 } |
|
264 |
|
265 public object OperationData1 |
|
266 { |
|
267 get { return iOperationData1; } |
|
268 set { iOperationData1 = value; } |
|
269 } |
|
270 |
|
271 public object OperationData2 |
|
272 { |
|
273 get { return iOperationData2; } |
|
274 set { iOperationData2 = value; } |
|
275 } |
|
276 |
|
277 public object OperationData3 |
|
278 { |
|
279 get { return iOperationData3; } |
|
280 set { iOperationData3 = value; } |
|
281 } |
|
282 #endregion |
|
283 |
|
284 #region Internal methods |
|
285 private string AppendFileExtension( string aFileName ) |
|
286 { |
|
287 System.Diagnostics.Debug.Assert( iContainer != null ); |
|
288 |
|
289 // Work out which extension we should be adding to the output |
|
290 string extensionToAppend = FileExtensionSuccess; |
|
291 if ( Container.Status == CIContainer.TStatus.EStatusErrorContainer ) |
|
292 { |
|
293 extensionToAppend = FileExtensionFailed; |
|
294 } |
|
295 |
|
296 // Then make the name |
|
297 string ret = aFileName; |
|
298 string extn = Path.GetExtension( aFileName ); |
|
299 // |
|
300 if ( extn.ToUpper() == extensionToAppend.ToUpper() ) |
|
301 { |
|
302 // Job done |
|
303 } |
|
304 else |
|
305 { |
|
306 ret += extensionToAppend; |
|
307 } |
|
308 // |
|
309 return ret; |
|
310 } |
|
311 |
|
312 private Stream TryToCreateStream( string aFileName, FileMode aMode ) |
|
313 { |
|
314 Stream ret = null; |
|
315 // |
|
316 try |
|
317 { |
|
318 // We do this inside a catch block because in multi-threaded situations, there |
|
319 // could be a race between the entity checking whether a file exists, and another |
|
320 // thread actually just about to create the file. The File.Exists() check just |
|
321 // avoids unnecessarily attempting to create the file if we *know* that it already |
|
322 // exists. The catch copes with the unexpected pre-emption. |
|
323 if ( !File.Exists( aFileName ) ) |
|
324 { |
|
325 ret = new FileStream( aFileName, aMode, FileAccess.Write, FileShare.None, 1024 * 12 ); |
|
326 } |
|
327 } |
|
328 catch ( IOException ) |
|
329 { |
|
330 } |
|
331 // |
|
332 return ret; |
|
333 } |
|
334 #endregion |
|
335 |
|
336 #region Internal constants |
|
337 private const int KMaxRetries = 100; |
|
338 #endregion |
|
339 |
|
340 #region Internal enumerations |
|
341 private enum TOutputMode |
|
342 { |
|
343 EOutputToFile = 0, |
|
344 EOutputToDirectory |
|
345 } |
|
346 #endregion |
|
347 |
|
348 #region Data members |
|
349 private readonly Version iUIVersion; |
|
350 private readonly string iUICommandLineArguments; |
|
351 private CIContainer iContainer; |
|
352 private TDetailLevel iDetailLevel = TDetailLevel.EFull; |
|
353 private string iFileExtensionSuccess = string.Empty; |
|
354 private string iFileExtensionFailed = string.Empty; |
|
355 private FileInfo iOutputFile; |
|
356 private DirectoryInfo iOutputDirectory; |
|
357 private TOutputMode iOutputMode = TOutputMode.EOutputToDirectory; |
|
358 private object iOperationData1 = null; |
|
359 private object iOperationData2 = null; |
|
360 private object iOperationData3 = null; |
|
361 #endregion |
|
362 } |
|
363 } |