|
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.Collections.Generic; |
|
19 using System.Text; |
|
20 using System.IO; |
|
21 using SymbianUtils; |
|
22 using SymbianUtils.Tracer; |
|
23 using SymbianUtils.Streams; |
|
24 using SymbianStructuresLib.Uids; |
|
25 using SymbianStructuresLib.Compression.Common; |
|
26 using SymbianImageLib.Common.Content; |
|
27 using SymbianImageLib.Common.Image; |
|
28 using SymbianImageLib.Common.Streams; |
|
29 using SymbianImageLib.E32Image.Image; |
|
30 using SymbianImageLib.E32Image.Header; |
|
31 |
|
32 namespace SymbianImageLib.E32Image.Content |
|
33 { |
|
34 public class SIContentE32Image : SIContent |
|
35 { |
|
36 #region Constructors |
|
37 internal SIContentE32Image( SymbianImageE32 aImage, string aName, uint aSize, long aImageContentOffset ) |
|
38 : base( aImage ) |
|
39 { |
|
40 iName = aName; |
|
41 iFileSize = aSize; |
|
42 iFileSize = aSize; |
|
43 } |
|
44 #endregion |
|
45 |
|
46 #region From SymbianImageContentFile |
|
47 public override TSymbianCompressionType CompressionType |
|
48 { |
|
49 get { return base.ImageHeader.CompressionType; } |
|
50 } |
|
51 |
|
52 public override string FileName |
|
53 { |
|
54 get { return iName; } |
|
55 } |
|
56 |
|
57 public override uint FileSize |
|
58 { |
|
59 get { return iFileSize; } |
|
60 } |
|
61 |
|
62 public override uint ContentSize |
|
63 { |
|
64 get |
|
65 { |
|
66 uint ret = 0; |
|
67 // |
|
68 lock ( iCodeSyncRoot ) |
|
69 { |
|
70 if ( iCode != null ) |
|
71 { |
|
72 ret = (uint) iCode.Length; |
|
73 } |
|
74 } |
|
75 // |
|
76 return ret; |
|
77 } |
|
78 } |
|
79 |
|
80 public override TCheckedUid Uid |
|
81 { |
|
82 get { return ImageHeader.Uid; } |
|
83 } |
|
84 |
|
85 public override byte[] GetAllData() |
|
86 { |
|
87 lock ( iCodeSyncRoot ) |
|
88 { |
|
89 return iCode; |
|
90 } |
|
91 } |
|
92 |
|
93 protected override uint DoProvideDataUInt32( uint aTranslatedAddress ) |
|
94 { |
|
95 uint ret = 0; |
|
96 // |
|
97 if ( iStream != null ) |
|
98 { |
|
99 using ( SymbianStreamReaderLE reader = SymbianStreamReaderLE.New( iStream, SymbianStreamReaderLE.TCloseOperation.ENone ) ) |
|
100 { |
|
101 reader.Seek( aTranslatedAddress ); |
|
102 ret = reader.ReadUInt32(); |
|
103 } |
|
104 } |
|
105 // |
|
106 return ret; |
|
107 } |
|
108 |
|
109 protected override ushort DoProvideDataUInt16( uint aTranslatedAddress ) |
|
110 { |
|
111 ushort ret = 0; |
|
112 // |
|
113 if ( iStream != null ) |
|
114 { |
|
115 using ( SymbianStreamReaderLE reader = SymbianStreamReaderLE.New( iStream, SymbianStreamReaderLE.TCloseOperation.ENone ) ) |
|
116 { |
|
117 reader.Seek( aTranslatedAddress ); |
|
118 ret = reader.ReadUInt16(); |
|
119 } |
|
120 } |
|
121 // |
|
122 return ret; |
|
123 } |
|
124 |
|
125 protected override void DoDecompress() |
|
126 { |
|
127 lock ( iCodeSyncRoot ) |
|
128 { |
|
129 if ( iCode == null ) |
|
130 { |
|
131 TSymbianCompressionType type = this.CompressionType; |
|
132 switch ( type ) |
|
133 { |
|
134 default: |
|
135 case TSymbianCompressionType.ENone: |
|
136 // NB: This has not yet been observed in reality |
|
137 DecompressNone(); |
|
138 break; |
|
139 case TSymbianCompressionType.EDeflate: |
|
140 case TSymbianCompressionType.EBytePair: |
|
141 { |
|
142 using ( SymbianDecompressor decompressor = SymbianDecompressor.NewByType( type ) ) |
|
143 { |
|
144 // |
|
145 switch ( type ) |
|
146 { |
|
147 case TSymbianCompressionType.EBytePair: |
|
148 DecompressBytePair( decompressor ); |
|
149 break; |
|
150 case TSymbianCompressionType.EDeflate: |
|
151 DecompressDeflate( decompressor ); |
|
152 break; |
|
153 } |
|
154 } |
|
155 break; |
|
156 } |
|
157 } |
|
158 |
|
159 if ( iCode != null ) |
|
160 { |
|
161 if ( iStream != null ) |
|
162 { |
|
163 iStream.Dispose(); |
|
164 iStream = null; |
|
165 } |
|
166 // |
|
167 iStream = new MemoryStream( iCode ); |
|
168 } |
|
169 } |
|
170 } |
|
171 } |
|
172 |
|
173 protected override bool GetIsContentPrepared() |
|
174 { |
|
175 lock ( iCodeSyncRoot ) |
|
176 { |
|
177 return ( iCode != null ); |
|
178 } |
|
179 } |
|
180 #endregion |
|
181 |
|
182 #region Properties |
|
183 public new SIHeaderE32Image ImageHeader |
|
184 { |
|
185 get { return (SIHeaderE32Image) base.ImageHeader; } |
|
186 } |
|
187 |
|
188 public new SymbianImageE32 Image |
|
189 { |
|
190 get { return (SymbianImageE32) base.Image; } |
|
191 } |
|
192 #endregion |
|
193 |
|
194 #region Internal methods |
|
195 private byte[] DecompressCommon( SymbianDecompressor aDecompressor, int aSeekOffset, int aAmountToRead, int aMaximumOutputSize, out int aNumberOfInputBytesRead ) |
|
196 { |
|
197 System.Diagnostics.Debug.WriteLine( "[SIContentE32Image] DecompressCommon - START - " + base.Image.Name + " # " + System.Threading.Thread.CurrentThread.Name ); |
|
198 // |
|
199 uint imageContentSize = iFileSize; |
|
200 uint orighdrsz = ImageHeader.TotalSize; |
|
201 uint remainder = imageContentSize - orighdrsz; |
|
202 // |
|
203 using ( SymbianStreamReaderLE reader = base.ImageStream.CreateReader( SymbianStreamReaderLE.TCloseOperation.EResetPosition ) ) |
|
204 { |
|
205 long codePos = Image.ContentOffsetWithinDataStream + orighdrsz + aSeekOffset; |
|
206 reader.Seek( codePos ); |
|
207 // |
|
208 byte[] input = reader.ReadBytes( aAmountToRead ); |
|
209 byte[] output = new byte[ aMaximumOutputSize ]; |
|
210 |
|
211 // The decompressor tells us how many bytes of output it really created. |
|
212 int numberOfBytesCreated = aDecompressor.DecompressImage( input, output, out aNumberOfInputBytesRead ); |
|
213 |
|
214 // We can then return that to the callee. |
|
215 byte[] ret = new byte[ numberOfBytesCreated > 0 ? numberOfBytesCreated : 0 ]; |
|
216 if ( numberOfBytesCreated > 0 ) |
|
217 { |
|
218 Array.Copy( output, ret, numberOfBytesCreated ); |
|
219 } |
|
220 // |
|
221 System.Diagnostics.Debug.WriteLine( "[SIContentE32Image] DecompressCommon - END - " + base.Image.Name + " # " + System.Threading.Thread.CurrentThread.Name ); |
|
222 // |
|
223 return ret; |
|
224 } |
|
225 } |
|
226 |
|
227 private void DecompressNone() |
|
228 { |
|
229 uint imageContentSize = iFileSize; |
|
230 uint orighdrsz = ImageHeader.TotalSize; |
|
231 uint uncompressedSize = ImageHeader.UncompressedSize; |
|
232 |
|
233 using ( SymbianStreamReaderLE reader = base.ImageStream.CreateReader( SymbianStreamReaderLE.TCloseOperation.EResetPosition ) ) |
|
234 { |
|
235 long codePos = Image.ContentOffsetWithinDataStream + orighdrsz; |
|
236 reader.Seek( codePos ); |
|
237 // |
|
238 lock ( iCodeSyncRoot ) |
|
239 { |
|
240 iCode = reader.ReadBytes( (int) uncompressedSize ); |
|
241 } |
|
242 } |
|
243 } |
|
244 |
|
245 private void DecompressBytePair( SymbianDecompressor aDecompressor ) |
|
246 { |
|
247 int inputBytesRead = 0; |
|
248 // |
|
249 uint imageContentSize = iFileSize; |
|
250 uint orighdrsz = ImageHeader.TotalSize; |
|
251 uint uncompressedSize = ImageHeader.UncompressedSize; |
|
252 |
|
253 // First decompress the code |
|
254 byte[] code = DecompressCommon( aDecompressor, 0, (int) ( imageContentSize - orighdrsz ), (int) uncompressedSize, out inputBytesRead ); |
|
255 if ( code.Length < ImageHeader.CodeSize ) |
|
256 { |
|
257 throw new Exception( "E32Image bytepair decompression did not provide enough code" ); |
|
258 } |
|
259 |
|
260 // Now get the data |
|
261 int remainder = (int) ( uncompressedSize - inputBytesRead ); |
|
262 byte[] data = DecompressCommon( aDecompressor, inputBytesRead, remainder, (int) uncompressedSize, out inputBytesRead ); |
|
263 |
|
264 // We should have read all the decompressed data |
|
265 int totalAmountOfDecompressedDataSupplied = data.Length + code.Length; |
|
266 if ( totalAmountOfDecompressedDataSupplied != uncompressedSize ) |
|
267 { |
|
268 throw new Exception( "E32Image bytepair decompression did not supply enough decompressed output" ); |
|
269 } |
|
270 |
|
271 lock ( iCodeSyncRoot ) |
|
272 { |
|
273 iCode = new byte[ uncompressedSize ]; |
|
274 Array.Copy( code, iCode, code.Length ); |
|
275 Array.Copy( data, 0, iCode, code.Length, data.Length ); |
|
276 } |
|
277 } |
|
278 |
|
279 private void DecompressDeflate( SymbianDecompressor aDecompressor ) |
|
280 { |
|
281 int inputBytesRead = 0; |
|
282 // |
|
283 uint imageContentSize = iFileSize; |
|
284 uint orighdrsz = ImageHeader.TotalSize; |
|
285 uint uncompressedSize = ImageHeader.UncompressedSize; |
|
286 |
|
287 byte[] combinedDataAndCode = DecompressCommon( aDecompressor, 0, (int) ( imageContentSize - orighdrsz ), (int) uncompressedSize, out inputBytesRead ); |
|
288 if ( combinedDataAndCode.Length != uncompressedSize ) |
|
289 { |
|
290 throw new Exception( "E32Image inflate decompression did not supply enough decompressed output" ); |
|
291 } |
|
292 |
|
293 lock ( iCodeSyncRoot ) |
|
294 { |
|
295 iCode = combinedDataAndCode; |
|
296 } |
|
297 } |
|
298 #endregion |
|
299 |
|
300 #region From DisposableObject |
|
301 protected override void CleanupManagedResources() |
|
302 { |
|
303 try |
|
304 { |
|
305 base.CleanupManagedResources(); |
|
306 } |
|
307 finally |
|
308 { |
|
309 if ( iStream != null ) |
|
310 { |
|
311 iStream.Dispose(); |
|
312 iStream = null; |
|
313 } |
|
314 } |
|
315 } |
|
316 #endregion |
|
317 |
|
318 #region Data members |
|
319 private readonly string iName; |
|
320 private readonly uint iFileSize; |
|
321 private byte[] iCode = null; |
|
322 private object iCodeSyncRoot = new object(); |
|
323 private MemoryStream iStream = null; |
|
324 #endregion |
|
325 } |
|
326 } |