|
1 /* |
|
2 * Copyright (c) 2008-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: Java Installer component iconconverter. |
|
15 * Reads icon and .jar file and stores it a temp file in a |
|
16 * format that can be shown by the S60 UI shell. |
|
17 * |
|
18 */ |
|
19 |
|
20 |
|
21 #include <zipfile.h> |
|
22 #include <time.h> |
|
23 |
|
24 #include "javacommonutils.h" |
|
25 #include "logger.h" |
|
26 #include "mifconverter.h" |
|
27 #include "iconconverter.h" |
|
28 |
|
29 namespace java |
|
30 { |
|
31 |
|
32 /** |
|
33 * The icon in S60 temporary drive |
|
34 */ |
|
35 _LIT(KTempIconName, "D:\\micon.mbm"); |
|
36 |
|
37 /** |
|
38 * The mask in S60 temporary drive |
|
39 */ |
|
40 _LIT(KTempMaskName, "D:\\mmask.mbm"); |
|
41 |
|
42 |
|
43 // MIF file constants |
|
44 const TInt KMifFileHeaderUid = 0x34232342; |
|
45 const TInt KMifFileHeaderVersion = 2; |
|
46 const TInt KMifFileHeaderLength = 2; |
|
47 |
|
48 const TInt KMifIconHeaderUid = 0x34232343; |
|
49 const TInt KMifIconHeaderVersion = 1; |
|
50 const TInt KMifIconHeaderType = 1; |
|
51 const TInt KMifIconHeaderAnimated = 0; |
|
52 |
|
53 |
|
54 |
|
55 CIconConverter* CIconConverter::NewL(RFs& aRFs) |
|
56 { |
|
57 return new(ELeave) CIconConverter(aRFs); |
|
58 } |
|
59 |
|
60 |
|
61 CIconConverter::CIconConverter(RFs &aRFs) |
|
62 { |
|
63 iRFs = aRFs; |
|
64 iImageDecoder = NULL; |
|
65 |
|
66 iBitmap = NULL; |
|
67 iBitmapMask = NULL; |
|
68 |
|
69 // In case there is no UI on the device ( as when installing an app or |
|
70 // MIDlet suite from PC ) make sure there is an instance of FBS running |
|
71 RFbsSession::Connect(); |
|
72 |
|
73 iActiveListener = NULL; |
|
74 } |
|
75 |
|
76 |
|
77 CIconConverter::~CIconConverter() |
|
78 { |
|
79 // Do NOT close file server session |
|
80 delete iBitmapMask; |
|
81 delete iBitmap; |
|
82 delete iImageDecoder; |
|
83 |
|
84 RFbsSession::Disconnect(); |
|
85 |
|
86 delete iActiveListener; |
|
87 } |
|
88 |
|
89 |
|
90 int CIconConverter::Convert( |
|
91 const TDesC &aJarFile, |
|
92 const TDesC &aIconFile, |
|
93 const TDesC &aOutputFile, |
|
94 TBool *apWasMbm) |
|
95 { |
|
96 int ret = 0; |
|
97 |
|
98 CActiveScheduler* pScheduler = NULL; |
|
99 |
|
100 if (NULL == CActiveScheduler::Current()) |
|
101 { |
|
102 // Must create active scheduler for this JNI thread |
|
103 // to be able to make asynchronous calls |
|
104 pScheduler = new CActiveScheduler(); |
|
105 CActiveScheduler::Install(pScheduler); |
|
106 } |
|
107 |
|
108 TRAPD(err, ret = ConvertL(aJarFile, aIconFile, aOutputFile, apWasMbm)); |
|
109 |
|
110 delete pScheduler; |
|
111 |
|
112 if (KErrNone != err) |
|
113 { |
|
114 return err; |
|
115 } |
|
116 |
|
117 return ret; |
|
118 } |
|
119 |
|
120 int CIconConverter::ConvertL( |
|
121 const TDesC &aJarFile, |
|
122 const TDesC &aIconFile, |
|
123 const TDesC &aOutputFile, |
|
124 TBool *apWasMbm) |
|
125 { |
|
126 // open jar file |
|
127 CZipFile *pZipFile = CZipFile::NewL(iRFs, aJarFile); |
|
128 CleanupStack::PushL(pZipFile); |
|
129 |
|
130 // try to open the icon inside the jar file |
|
131 CZipFileMember *pZipMember = NULL; |
|
132 // Does the icon name start with '/' |
|
133 if (aIconFile.Locate('/') == 0) |
|
134 { |
|
135 // remove the leading '/' character |
|
136 TFileName tempName = aIconFile.Right(aIconFile.Length() - 1); |
|
137 pZipMember = pZipFile->MemberL(tempName); |
|
138 } |
|
139 else |
|
140 { |
|
141 pZipMember = pZipFile->MemberL(aIconFile); |
|
142 } |
|
143 |
|
144 if (NULL == pZipMember) |
|
145 { |
|
146 LOG(EJavaInstaller, EInfo, "Cannot find icon inside .jar file"); |
|
147 User::Leave(KErrNotFound); |
|
148 } |
|
149 CleanupStack::PushL(pZipMember); |
|
150 |
|
151 // reserve buffer for uncompressed icon |
|
152 TUint32 iconSize = pZipMember->UncompressedSize(); |
|
153 HBufC8* pIconBuf = HBufC8::NewL(iconSize); |
|
154 CleanupStack::PushL(pIconBuf); |
|
155 TPtr8 ptrIconBuf(NULL, 0); |
|
156 ptrIconBuf.Set(pIconBuf->Des()); |
|
157 |
|
158 RZipFileMemberReaderStream *pReader = NULL; |
|
159 User::LeaveIfError(pZipFile->GetInputStreamL(pZipMember, pReader)); |
|
160 CleanupStack::PushL(pReader); |
|
161 |
|
162 // read icon to buffer |
|
163 User::LeaveIfError(pReader->Read(ptrIconBuf, iconSize)); |
|
164 CleanupStack::PopAndDestroy(pReader); |
|
165 |
|
166 // free unnecessary objects |
|
167 CleanupStack::Pop(pIconBuf); // this is still needed |
|
168 CleanupStack::PopAndDestroy(pZipMember); |
|
169 CleanupStack::PopAndDestroy(pZipFile); |
|
170 |
|
171 CleanupStack::PushL(pIconBuf); |
|
172 |
|
173 // Icon buffer contains SVG icon if the content of the buffer |
|
174 // starts with _L8("<?xml") |
|
175 if ((iconSize > 5) && |
|
176 (ptrIconBuf[0] == 0x3c) && |
|
177 (ptrIconBuf[1] == 0x3f) && |
|
178 (ptrIconBuf[2] == 0x78) && |
|
179 (ptrIconBuf[3] == 0x6d) && |
|
180 (ptrIconBuf[4] == 0x6c)) |
|
181 { |
|
182 *apWasMbm = EFalse; |
|
183 return ConvertScalableIconL(pIconBuf, aOutputFile); |
|
184 } |
|
185 else |
|
186 { |
|
187 *apWasMbm = ETrue; |
|
188 return ConvertNormalIconL(pIconBuf, ptrIconBuf, aOutputFile); |
|
189 } |
|
190 } |
|
191 |
|
192 int CIconConverter::ConvertNormalIconL( |
|
193 HBufC8* apIconBuf, |
|
194 TPtr8& aptrIconBuf, |
|
195 const TDesC &aOutputFile) |
|
196 { |
|
197 // convert icon in buffer to bitmap |
|
198 if (NULL == iImageDecoder) |
|
199 { |
|
200 // create image decoder if not yet created |
|
201 iImageDecoder = CBufferedImageDecoder::NewL(iRFs); |
|
202 } |
|
203 |
|
204 // Try to create a decoder implementation for the image in the buffer |
|
205 TRAPD(err, iImageDecoder->OpenL(aptrIconBuf)); |
|
206 if (KErrNotFound == err) |
|
207 { |
|
208 // If the format is unrecognised AND the first 2 bytes are 0 then |
|
209 // we assume it is a WBMP. |
|
210 // The first two bytes of other formats (e.g. ico) may also begin with 0, 0 |
|
211 // but they should have already been recognised by the first call to OpenL. |
|
212 if (((*apIconBuf)[0] == 0) && ((*apIconBuf)[1] == 0)) |
|
213 { |
|
214 delete iImageDecoder; |
|
215 iImageDecoder = NULL; |
|
216 iImageDecoder = CBufferedImageDecoder::NewL(iRFs); |
|
217 WLOG(EJavaInstaller, "CIconConverter::ConvertNormalIconL - Format " |
|
218 "can't be fully identified, assuming this is WBMP"); |
|
219 _LIT8(KWBMPMimeType, "image/vnd.wap.wbmp"); |
|
220 iImageDecoder->OpenL(aptrIconBuf, KWBMPMimeType); |
|
221 err = KErrNone; |
|
222 } |
|
223 } |
|
224 // Leave if we could not recover from error |
|
225 User::LeaveIfError(err); |
|
226 |
|
227 // get info concerning the icon |
|
228 TFrameInfo frameInfo = iImageDecoder->FrameInfo(0); |
|
229 |
|
230 // create bitmap for icon |
|
231 iBitmap = new(ELeave) CFbsBitmap; |
|
232 User::LeaveIfError(iBitmap->Create(frameInfo.iOverallSizeInPixels, EColor16M)); |
|
233 |
|
234 // create bitmap for mask |
|
235 iBitmapMask = new(ELeave) CFbsBitmap; |
|
236 User::LeaveIfError(iBitmapMask->Create(frameInfo.iOverallSizeInPixels, EGray256)); |
|
237 |
|
238 // Convert icon to bitmap and possible mask. |
|
239 // Wait until the asynch conversion has been done. |
|
240 iActiveListener = new(ELeave) CActiveListener(); |
|
241 iActiveListener->InitialiseActiveListener(); |
|
242 |
|
243 // Note that this does not generate mask if the image does not contain it |
|
244 iImageDecoder->Convert(&(iActiveListener->iStatus), |
|
245 *iBitmap, |
|
246 *iBitmapMask); |
|
247 |
|
248 CActiveScheduler::Start(); |
|
249 err = iActiveListener->iStatus.Int(); |
|
250 delete iActiveListener; |
|
251 iActiveListener = NULL; |
|
252 if (err != KErrNone) |
|
253 { |
|
254 User::Leave(err); |
|
255 } |
|
256 |
|
257 // store bitmap to two temp files |
|
258 User::LeaveIfError(iBitmap->Save(KTempIconName)); |
|
259 User::LeaveIfError(iBitmapMask->Save(KTempMaskName)); |
|
260 |
|
261 // construct multi bitmap file from bitmap and mask files (2 files) |
|
262 TInt32 sourceIds[] = {0, 0}; |
|
263 TFileName** filenames = new(ELeave) TFileName*[2]; |
|
264 CleanupStack::PushL(filenames); |
|
265 filenames[0] = new(ELeave) TFileName(KTempIconName); |
|
266 CleanupStack::PushL(filenames[0]); |
|
267 filenames[1] = new(ELeave) TFileName(KTempMaskName); |
|
268 CleanupStack::PushL(filenames[1]); |
|
269 |
|
270 CFbsBitmap::StoreL(aOutputFile, 2, (const TDesC**)filenames, sourceIds); |
|
271 |
|
272 // Now try to delete the temp icon and mask files, |
|
273 // ignore possible errors |
|
274 (void)iRFs.Delete(KTempIconName); |
|
275 (void)iRFs.Delete(KTempMaskName); |
|
276 |
|
277 CleanupStack::PopAndDestroy(filenames[1]); |
|
278 CleanupStack::PopAndDestroy(filenames[0]); |
|
279 CleanupStack::PopAndDestroy(filenames); |
|
280 CleanupStack::PopAndDestroy(apIconBuf); |
|
281 |
|
282 return KErrNone; |
|
283 } |
|
284 |
|
285 int CIconConverter::ConvertScalableIconL( |
|
286 HBufC8* apIconBuf, |
|
287 const TDesC &aOutputFile) |
|
288 { |
|
289 TInt iconDataSize = apIconBuf->Length(); |
|
290 |
|
291 // File header |
|
292 TMifFileHeader fileHeader; |
|
293 fileHeader.iUid = KMifFileHeaderUid; |
|
294 fileHeader.iVersion = KMifFileHeaderVersion; |
|
295 fileHeader.iOffset = sizeof(fileHeader); |
|
296 fileHeader.iLength = KMifFileHeaderLength; // number of indexes |
|
297 |
|
298 // Icon offset element |
|
299 TMifIconOffset iconOffset; |
|
300 iconOffset.iIconOffset = |
|
301 sizeof(fileHeader) + |
|
302 sizeof(iconOffset) * KMifFileHeaderLength; // mif header + icon offset |
|
303 iconOffset.iIconLength = |
|
304 sizeof(TMifIconHeader) + iconDataSize; //icon header + icon data |
|
305 |
|
306 // Icon header |
|
307 TMifIconHeader iconHeader; |
|
308 iconHeader.iUid = KMifIconHeaderUid; |
|
309 iconHeader.iVersion = KMifIconHeaderVersion; |
|
310 iconHeader.iOffset = sizeof(iconHeader); // dataOffset |
|
311 iconHeader.iLength = iconDataSize; // dataLength |
|
312 iconHeader.iType = KMifIconHeaderType; // svg |
|
313 iconHeader.iDepth = EColor16M; |
|
314 iconHeader.iAnimated = KMifIconHeaderAnimated; |
|
315 iconHeader.iMaskDepth = EColor16M; |
|
316 |
|
317 // Create MIFConverter class |
|
318 CMifConverter* mifConverter = CMifConverter::NewL(iRFs, aOutputFile); |
|
319 CleanupStack::PushL(mifConverter); |
|
320 |
|
321 // write mif file header |
|
322 mifConverter->WriteMifFileHeaderL(fileHeader); |
|
323 // insert 2 iconOffset elements: first for the image, the other for the mask |
|
324 mifConverter->WriteMifIconOffsetL(iconOffset); |
|
325 mifConverter->WriteMifIconOffsetL(iconOffset); |
|
326 mifConverter->WriteMifIconHeaderL(iconHeader); |
|
327 |
|
328 // write mif file body |
|
329 mifConverter->WriteMifBodyL(apIconBuf); |
|
330 |
|
331 // cleanup |
|
332 CleanupStack::PopAndDestroy(mifConverter); |
|
333 CleanupStack::PopAndDestroy(apIconBuf); |
|
334 |
|
335 return KErrNone; |
|
336 } |
|
337 |
|
338 void CIconConverter:: LogAllSupportedMimeTypes() |
|
339 { |
|
340 // List the file extensions that can be decoded and their corresponding MIME types |
|
341 |
|
342 RFileExtensionMIMETypeArray mimeTypes; |
|
343 CImageDecoder::GetFileTypesL(mimeTypes); |
|
344 TInt nTypes = mimeTypes.Count(); |
|
345 |
|
346 for (TInt nInd = 0; nInd < nTypes; nInd++) |
|
347 { |
|
348 const TDesC& extension = mimeTypes[nInd]->FileExtension(); |
|
349 // Reserve one char for null terminator |
|
350 HBufC* extBuf = HBufC::NewLC(extension.Length() + 1); |
|
351 TPtr extPtr(extBuf->Des()); |
|
352 extPtr.Append(extension); |
|
353 LOG1WSTR(EJavaInstaller, EInfo, |
|
354 "Icon converter supports file extension %s", |
|
355 (wchar_t *)(extPtr.PtrZ())); |
|
356 CleanupStack::Pop(extBuf); |
|
357 |
|
358 const TDesC8& mime = mimeTypes[nInd]->MIMEType(); |
|
359 HBufC8* mimeBuf = HBufC8::NewLC(mime.Length() + 1); |
|
360 TPtr8 mimePtr(mimeBuf->Des()); |
|
361 mimePtr.Append(mime); |
|
362 LOG1( |
|
363 EJavaInstaller, |
|
364 EInfo, |
|
365 "Icon converter supports MIME type %s", |
|
366 mimePtr.PtrZ()); |
|
367 |
|
368 CleanupStack::Pop(mimeBuf); |
|
369 } |
|
370 |
|
371 mimeTypes.ResetAndDestroy(); |
|
372 } |
|
373 |
|
374 } // namespace java |