|
1 /* |
|
2 * Copyright (c) 1997-1999 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 |
|
18 |
|
19 |
|
20 #include "rescomp.h" |
|
21 #include <e32cons.h> |
|
22 #include <s32file.h> |
|
23 #include <s32mem.h> |
|
24 |
|
25 #include <barsc.h> |
|
26 |
|
27 #include "resdict.h" |
|
28 #include "resentry.h" |
|
29 |
|
30 //#define __DEBUG_WRITE_UNCOMPRESSED_BAFL_RESOURCE |
|
31 |
|
32 // TBit Writer |
|
33 |
|
34 TBitWriter::TBitWriter(RWriteStream& aStream) |
|
35 :iStream(aStream) |
|
36 { |
|
37 iValue = 0; |
|
38 iBitsWritten = 0; |
|
39 } |
|
40 |
|
41 void TBitWriter::WriteL(TInt aValue, TInt aBits) |
|
42 { |
|
43 // 1<< aBits is the max Value; |
|
44 |
|
45 __ASSERT_DEBUG((1<<aBits) > aValue, User::Panic(_L("TBitWriter"),KErrOverflow)); |
|
46 if (aBits + iBitsWritten < 8) |
|
47 { |
|
48 // Not enough data to write a byte |
|
49 iValue += (aValue << iBitsWritten); |
|
50 iBitsWritten += aBits; |
|
51 } |
|
52 else |
|
53 { |
|
54 TInt bitsLeft = 8-iBitsWritten; |
|
55 TInt mask = (1<<bitsLeft)-1; |
|
56 TInt maskValue = (aValue & mask) << iBitsWritten; |
|
57 |
|
58 iValue += maskValue; |
|
59 iStream.WriteUint8L(iValue); |
|
60 // RDebug::Print(_L("Writing: %b [0x%x]"), iValue, iValue); |
|
61 |
|
62 TInt newValue = aValue >> bitsLeft; |
|
63 TInt bits = aBits - bitsLeft; |
|
64 while (bits > 7) |
|
65 { |
|
66 iStream.WriteUint8L(newValue & 0xff); |
|
67 bits -= 8; |
|
68 newValue = (newValue >> 8); |
|
69 } |
|
70 iValue = newValue; |
|
71 iBitsWritten=bits; |
|
72 } |
|
73 } |
|
74 |
|
75 void TBitWriter::FlushL() |
|
76 { |
|
77 if (iBitsWritten > 0) |
|
78 { |
|
79 iStream.WriteUint8L(iValue); |
|
80 iValue = 0; |
|
81 iBitsWritten=0; |
|
82 } |
|
83 } |
|
84 |
|
85 |
|
86 |
|
87 |
|
88 CResComp::CResComp(CConsoleBase* aConsole) |
|
89 :iConsole(aConsole) |
|
90 { |
|
91 } |
|
92 |
|
93 CResComp::~CResComp() |
|
94 { |
|
95 if (iResArray) |
|
96 { |
|
97 iResArray->ResetAndDestroy(); |
|
98 } |
|
99 delete iResArray; |
|
100 delete iResData; |
|
101 delete iDict; |
|
102 } |
|
103 |
|
104 |
|
105 void CResComp::LoadBAFLCompressedFileL(RFs& aFs, const TDesC& aName) |
|
106 { |
|
107 |
|
108 RResourceFile res; |
|
109 res.OpenL(aFs, aName); |
|
110 CleanupClosePushL(res); |
|
111 |
|
112 // Count resources |
|
113 TInt count = 0; |
|
114 |
|
115 // This code around ConfirmSigniture had to be added because some S60 resources don't seem to have signature and panic. |
|
116 // See DEF019933 - RResourceFile::ConfirmSignatureL() needs to be more robust |
|
117 |
|
118 HBufC8* const resource=res.AllocReadLC(1); |
|
119 if(resource->Length()==8) // 8 =Sizeof SSigRecord |
|
120 { |
|
121 res.ConfirmSignatureL(0); |
|
122 } |
|
123 CleanupStack::PopAndDestroy(resource); |
|
124 |
|
125 TInt offset = res.Offset(); |
|
126 while (res.OwnsResourceId(count+offset+1)) |
|
127 { |
|
128 count++; |
|
129 }; |
|
130 |
|
131 const TInt KBufferGranularity = 1000; |
|
132 CBufFlat* buffer = CBufFlat::NewL(KBufferGranularity); |
|
133 CleanupStack::PushL(buffer); |
|
134 |
|
135 CBufFlat* indexbuffer = CBufFlat::NewL(KBufferGranularity); |
|
136 CleanupStack::PushL(indexbuffer); |
|
137 |
|
138 RBufWriteStream stream; |
|
139 stream.Open(*buffer); |
|
140 CleanupClosePushL(stream); |
|
141 |
|
142 RBufWriteStream indexstream; |
|
143 indexstream.Open(*indexbuffer); |
|
144 CleanupClosePushL(indexstream); |
|
145 |
|
146 TInt total = 0; |
|
147 |
|
148 for (TInt ii=0; ii<count; ii++) |
|
149 { |
|
150 indexstream.WriteUint16L(total+4); |
|
151 HBufC8* data = res.AllocReadLC(ii+offset+1); |
|
152 TInt len = data->Length(); |
|
153 total += len; |
|
154 stream.WriteL(*data, len); |
|
155 CleanupStack::PopAndDestroy(); |
|
156 } |
|
157 indexstream.WriteUint16L(total+4); |
|
158 |
|
159 |
|
160 indexstream.CommitL(); |
|
161 CleanupStack::PopAndDestroy(); // close indexstream |
|
162 |
|
163 stream.CommitL(); |
|
164 CleanupStack::PopAndDestroy(); // close stream |
|
165 |
|
166 CBufFlat* outputBuffer = CBufFlat::NewL(KBufferGranularity); |
|
167 CleanupStack::PushL(outputBuffer); |
|
168 |
|
169 RBufWriteStream outStream; |
|
170 outStream.Open(*outputBuffer); |
|
171 CleanupClosePushL(outStream); |
|
172 |
|
173 |
|
174 outStream.WriteUint16L(total + 4); // 4 byte header |
|
175 outStream.WriteUint16L(((count+1)*2)+1); |
|
176 |
|
177 TPtr8 ptr = buffer->Ptr(0); |
|
178 outStream.WriteL(ptr.Ptr(), ptr.Length()); |
|
179 TPtr8 indexptr = indexbuffer->Ptr(0); |
|
180 outStream.WriteL(indexptr.Ptr(), indexptr.Length()); |
|
181 outStream.CommitL(); |
|
182 CleanupStack::PopAndDestroy();// outStream |
|
183 |
|
184 |
|
185 /* DEBUG - OUTPUT UNCOMPRESSED REPRESENTATION TO A FILE - FOR VERIFICATION */ |
|
186 #ifdef __DEBUG_WRITE_UNCOMPRESSED_BAFL_RESOURCE |
|
187 { |
|
188 TFileName newName(aName); |
|
189 newName.Append(_L(".ER5u")); |
|
190 |
|
191 RFileWriteStream outStream; |
|
192 User::LeaveIfError(outStream.Replace(aFs, newName, EFileWrite)); |
|
193 CleanupClosePushL(outStream); |
|
194 |
|
195 |
|
196 outStream.WriteUint16L(total + 4); // 4 byte header |
|
197 outStream.WriteUint16L(((count+1)*2)+1); |
|
198 |
|
199 TPtr8 ptr = buffer->Ptr(0); |
|
200 outStream.WriteL(ptr.Ptr(), ptr.Length()); |
|
201 TPtr8 indexptr = indexbuffer->Ptr(0); |
|
202 outStream.WriteL(indexptr.Ptr(), indexptr.Length()); |
|
203 outStream.CommitL(); |
|
204 CleanupStack::PopAndDestroy(); // outStream |
|
205 } |
|
206 #endif /* END __DEBUG_WRITE_UNCOMPRESSED_BAFL_RESOURCE */ |
|
207 |
|
208 iDict = new(ELeave)CDictArray(); |
|
209 |
|
210 iFileLength = outputBuffer->Size(); |
|
211 |
|
212 iResData = (TUint8*)User::AllocL(iFileLength); |
|
213 |
|
214 Mem::Copy(iResData, const_cast<TUint8*>(outputBuffer->Ptr(0).Ptr()), iFileLength ); |
|
215 |
|
216 CleanupStack::PopAndDestroy(outputBuffer); |
|
217 |
|
218 CleanupStack::PopAndDestroy(indexbuffer); |
|
219 CleanupStack::PopAndDestroy(buffer); |
|
220 |
|
221 CleanupStack::PopAndDestroy(); // res |
|
222 |
|
223 // Need to keep original size in order to compare with new compression for IsValid() |
|
224 TEntry entry; |
|
225 if( aFs.Entry(aName, entry) ==KErrNone) |
|
226 { |
|
227 iOriginalCompressedSize = entry.iSize; |
|
228 } |
|
229 |
|
230 } |
|
231 |
|
232 TBool CResComp::FileIsBAFLCompressedL(RFs& aFs, const TDesC& aFileName) |
|
233 { |
|
234 const TUid KBAFLCompressedFileUid = {0x101f4a6b}; // rcomp unicode compressed |
|
235 |
|
236 TEntry entry; |
|
237 User::LeaveIfError(aFs.Entry(aFileName,entry)); |
|
238 |
|
239 return entry.IsUidPresent(KBAFLCompressedFileUid); |
|
240 } |
|
241 |
|
242 void CResComp::LoadFileL(RFs& aFs, const TDesC& aFileName) |
|
243 { |
|
244 ASSERT(iDict==NULL); |
|
245 |
|
246 TParsePtrC parse(aFileName); |
|
247 iConOutput.Format(parse.NameAndExt()); |
|
248 iConOutput.Append(_L("\t")); |
|
249 if (parse.NameAndExt().Length() < 16) |
|
250 { |
|
251 iConOutput.Append(_L("\t")); |
|
252 } |
|
253 |
|
254 if(FileIsBAFLCompressedL(aFs, aFileName)) |
|
255 { |
|
256 LoadBAFLCompressedFileL(aFs, aFileName); |
|
257 } |
|
258 else |
|
259 { |
|
260 LoadUnCompressedFileL(aFs, aFileName); |
|
261 } |
|
262 |
|
263 } |
|
264 |
|
265 void CResComp::LoadUnCompressedFileL(RFs& aFs, const TDesC& aFileName) |
|
266 { |
|
267 |
|
268 iDict = new(ELeave)CDictArray(); |
|
269 |
|
270 TEntry entry; |
|
271 User::LeaveIfError( aFs.Entry(aFileName, entry) ); |
|
272 iFileLength = entry.iSize; |
|
273 |
|
274 iResData = (TUint8*)User::AllocL(entry.iSize + 2); // +2 for file size |
|
275 |
|
276 RFileReadStream stream; |
|
277 User::LeaveIfError( stream.Open(aFs, aFileName, EFileRead) ); |
|
278 CleanupClosePushL(stream); |
|
279 stream.ReadL(iResData, entry.iSize); |
|
280 CleanupStack::PopAndDestroy(); // stream |
|
281 } |
|
282 |
|
283 |
|
284 void CResComp::CompressL() |
|
285 { |
|
286 if (iFileLength == 0) |
|
287 { |
|
288 iCompressedSize = iFileLength; |
|
289 return; |
|
290 } |
|
291 |
|
292 TUint16* resData16 = (TUint16*)iResData; |
|
293 TInt indexOffset = resData16[0]; |
|
294 TInt indexLength = resData16[1]; |
|
295 |
|
296 if (indexOffset == 4) |
|
297 { |
|
298 // File is already compressed |
|
299 iCompressedSize = iFileLength; |
|
300 return; |
|
301 } |
|
302 |
|
303 if (indexOffset > iFileLength) |
|
304 { |
|
305 iCompressedSize = iFileLength; |
|
306 return; |
|
307 } |
|
308 |
|
309 iResources = (indexLength / 2) - 1; |
|
310 |
|
311 // iConsole->Printf(_L("Resources: %d\n"), iResources); |
|
312 |
|
313 // iConOutput.AppendFormat(_L("%d\t\t"), iResources); |
|
314 |
|
315 |
|
316 iResIndex = (TUint16*)(iResData + indexOffset); |
|
317 |
|
318 |
|
319 iResArray = new(ELeave)CArrayPtrFlat<CResEntry>(10); |
|
320 |
|
321 iResIndex[iResources] = (TUint16)(iFileLength-((iResources+1) * 2)); // end of file - index |
|
322 |
|
323 // Build dictionary |
|
324 |
|
325 // iConsole->Printf(_L("Building Dictionary\n")); |
|
326 |
|
327 for (TInt ii=0; ii<iResources; ii++) |
|
328 { |
|
329 TBuf<80> lineOut(_L("\r")); |
|
330 lineOut.Append(iConOutput); |
|
331 lineOut.AppendFormat(_L("%3d / %3d"), ii+1, iResources); |
|
332 iConsole->Printf(lineOut); |
|
333 // iConsole->Printf(_L("\r%d / %d"), ii+1, iResources); |
|
334 CResEntry* rEntry = new(ELeave)CResEntry(iDict); |
|
335 CleanupStack::PushL(rEntry); |
|
336 |
|
337 TInt resSize = iResIndex[ii+1] - iResIndex[ii]; |
|
338 if (resSize > iLargestResourceSize) |
|
339 iLargestResourceSize = resSize; |
|
340 |
|
341 rEntry->AddPlainDataL(iResData+iResIndex[ii], iResIndex[ii+1] - iResIndex[ii]); |
|
342 iResArray->AppendL(rEntry); |
|
343 CleanupStack::Pop(); //rEntry |
|
344 |
|
345 |
|
346 rEntry->MatchSelfL(ii, this); |
|
347 } |
|
348 |
|
349 // Compress using dictionary |
|
350 |
|
351 |
|
352 // iConsole->Printf(_L("\nCompressing\n")); |
|
353 |
|
354 CDictArray* backupDict = iDict->DuplicateL(); |
|
355 CleanupStack::PushL(backupDict); |
|
356 |
|
357 AttemptCompressionL(32); |
|
358 iDict = backupDict->DuplicateL(); |
|
359 AttemptCompressionL(64); |
|
360 iDict = backupDict->DuplicateL(); |
|
361 AttemptCompressionL(128); |
|
362 iDict = backupDict->DuplicateL(); |
|
363 AttemptCompressionL(256); |
|
364 iDict = backupDict->DuplicateL(); |
|
365 AttemptCompressionL(512); |
|
366 iDict = backupDict->DuplicateL(); |
|
367 |
|
368 |
|
369 CompressResourcesL(iBestCompression); |
|
370 |
|
371 |
|
372 CleanupStack::PopAndDestroy(); // backupDict |
|
373 } |
|
374 |
|
375 TInt CResComp::AttemptCompressionL(TInt aDictEntries) |
|
376 { |
|
377 TInt size = CompressResourcesL(aDictEntries); |
|
378 // RDebug::Print(_L("Entries: %d Size:%d"), aDictEntries, size); |
|
379 |
|
380 TBool valid = IsValid(); |
|
381 if (!valid) |
|
382 { |
|
383 RDebug::Print(_L("Compression Not Valid")); |
|
384 } |
|
385 |
|
386 if ((size < iBestSize || iBestSize == 0) && valid) |
|
387 { |
|
388 iBestCompression = aDictEntries; |
|
389 iBestSize = size; |
|
390 } |
|
391 delete iDict; |
|
392 iDict = NULL; |
|
393 return size; |
|
394 } |
|
395 |
|
396 |
|
397 TInt CResComp::CompressResourcesL(TInt aDictEntries) |
|
398 { |
|
399 iMaxEntries = aDictEntries; |
|
400 iBitsForDict = 0; |
|
401 while ( (1<<iBitsForDict) < aDictEntries) |
|
402 { |
|
403 iBitsForDict++; |
|
404 } |
|
405 iDict->iDictionaryBits = iBitsForDict; |
|
406 // RDebug::Print(_L("Entries: %d Bits: %d"), aDictEntries, iBitsForDict); |
|
407 iResArray->ResetAndDestroy(); |
|
408 // Reset dictionary count |
|
409 |
|
410 TInt dCount = iDict->Count(); |
|
411 for (TInt ll=0; ll<dCount; ll++) |
|
412 { |
|
413 iDict->At(ll).iUses = 0; |
|
414 } |
|
415 |
|
416 for (TInt kk=0; kk<iResources; kk++) |
|
417 { |
|
418 CResEntry* rEntry = new(ELeave)CResEntry(iDict); |
|
419 CleanupStack::PushL(rEntry); |
|
420 rEntry->AddPlainDataL(iResData+iResIndex[kk], iResIndex[kk+1] - iResIndex[kk]); |
|
421 rEntry->MatchDictL(); |
|
422 iResArray->AppendL(rEntry); |
|
423 CleanupStack::Pop(); // rEntry |
|
424 } |
|
425 |
|
426 |
|
427 // Optimize Dictionary |
|
428 |
|
429 OptimizeDict(); |
|
430 |
|
431 // Compress using optimized dictionary |
|
432 |
|
433 dCount = iDict->Count(); |
|
434 for (TInt x=0; x<dCount; x++) |
|
435 { |
|
436 iDict->At(x).iUses = 0; |
|
437 } |
|
438 |
|
439 iResArray->ResetAndDestroy(); |
|
440 for (TInt xx=0; xx<iResources; xx++) |
|
441 { |
|
442 CResEntry* rEntry = new(ELeave)CResEntry(iDict); |
|
443 CleanupStack::PushL(rEntry); |
|
444 rEntry->AddPlainDataL(iResData+iResIndex[xx], iResIndex[xx+1] - iResIndex[xx]); |
|
445 rEntry->MatchDictL(); |
|
446 iResArray->AppendL(rEntry); |
|
447 CleanupStack::Pop(); // rEntry |
|
448 } |
|
449 |
|
450 |
|
451 // Make sure that there is no more than 256 data bytes in each resource component |
|
452 CheckForLongDataStringsL(); |
|
453 |
|
454 TInt size = ResourceSize(); |
|
455 |
|
456 TInt count = iResArray->Count(); |
|
457 |
|
458 size += 4; // res header |
|
459 size += 7; // dict header |
|
460 size += (count + 1) * 2; // res index |
|
461 |
|
462 TInt dSize = iDict->DictionarySize(); |
|
463 |
|
464 iCompressedSize = size+dSize; |
|
465 return size+dSize; |
|
466 } |
|
467 |
|
468 TInt CResComp::ResourceSize() |
|
469 { |
|
470 TInt resSize = 0; |
|
471 if (!iResArray) |
|
472 return -1; |
|
473 TInt count = iResArray->Count(); |
|
474 for (TInt jj=0; jj<count; jj++) |
|
475 { |
|
476 resSize += ((iResArray->At(jj))->Size(iBitsForDict)); |
|
477 } |
|
478 resSize = (resSize + 7) / 8; |
|
479 return resSize; |
|
480 } |
|
481 |
|
482 |
|
483 |
|
484 |
|
485 TBool CResComp::IsValid() |
|
486 { |
|
487 TInt resSize = ResourceSize(); |
|
488 TInt dSize = iDict->DictionarySizeWithoutIndex(); |
|
489 |
|
490 RDebug::Print(_L("Ressize = %D, dsize=%D, compressedsize=%D , fileSize=%D\n"), resSize, dSize, CompressedSize(), OriginalFileSize()); |
|
491 |
|
492 if (resSize < 8192 && dSize < 8192 && (CompressedSize() < OriginalFileSize()) && resSize > 0) |
|
493 { |
|
494 return ETrue; |
|
495 } |
|
496 return EFalse; |
|
497 } |
|
498 |
|
499 |
|
500 |
|
501 |
|
502 |
|
503 |
|
504 |
|
505 |
|
506 void CResComp::WriteFileL(RFs& aFs, const TDesC& aName) |
|
507 { |
|
508 CBufFlat* buffer = CBufFlat::NewL(1024); |
|
509 CleanupStack::PushL(buffer); |
|
510 |
|
511 RBufWriteStream bStream; |
|
512 bStream.Open(*buffer); |
|
513 CleanupClosePushL(bStream); |
|
514 |
|
515 |
|
516 RFileWriteStream fStream; |
|
517 User::LeaveIfError(fStream.Replace(aFs, aName, EFileWrite)); |
|
518 |
|
519 WriteHeaderL(fStream); |
|
520 WriteDictionaryL(fStream); |
|
521 WriteResourceL(fStream); |
|
522 |
|
523 fStream.Close(); |
|
524 |
|
525 CleanupStack::PopAndDestroy(2); // bStream, buffer |
|
526 } |
|
527 |
|
528 |
|
529 |
|
530 void CResComp::OptimizeDict() |
|
531 { |
|
532 // Find referenced dicts |
|
533 TInt entries = iDict->Count(); |
|
534 |
|
535 for (TInt ii=0; ii<entries-1; ii++) |
|
536 { |
|
537 TBuf8<KMaxDictEntry> dc; |
|
538 dc.Copy(iDict->At(ii).iData); |
|
539 |
|
540 FindEmbeddedDict(dc, ii+1); |
|
541 } |
|
542 |
|
543 // Sort dictionary in order of use |
|
544 |
|
545 CDictArray* newDict = new(ELeave)CDictArray(); |
|
546 CleanupStack::PushL(newDict); |
|
547 |
|
548 for (TInt jj=0; jj<entries; jj++) |
|
549 { |
|
550 newDict->OrderedInsertL(iDict->At(jj)); |
|
551 } |
|
552 |
|
553 TInt newDictEntries = newDict->Count(); |
|
554 if (newDictEntries > iMaxEntries) |
|
555 newDictEntries = iMaxEntries; |
|
556 |
|
557 iDict->Reset(); |
|
558 |
|
559 for (TInt kk=0; kk<newDictEntries; kk++) |
|
560 { |
|
561 iDict->SizedInsertL(newDict->At(kk)); |
|
562 } |
|
563 |
|
564 CleanupStack::PopAndDestroy(); // newDict |
|
565 |
|
566 for (TInt zz=0; zz<newDictEntries; zz++) |
|
567 { |
|
568 iDict->At(zz).CreateEmbeddedDict(zz, iDict); |
|
569 } |
|
570 } |
|
571 |
|
572 |
|
573 void CResComp::FindEmbeddedDict(TDesC8& aMatch, TInt aStart) |
|
574 { |
|
575 TInt entries = iDict->Count(); |
|
576 for (TInt ii=aStart; ii<entries; ii++) |
|
577 { |
|
578 TInt found = aMatch.Find(iDict->At(ii).iData); |
|
579 if (found != KErrNotFound) |
|
580 { |
|
581 // Found embedded dict |
|
582 iDict->At(ii).iRef++; |
|
583 if (found > 1) |
|
584 { |
|
585 TPtrC8 left = aMatch.Left(found); |
|
586 FindEmbeddedDict(left, ii); |
|
587 } |
|
588 TInt right = aMatch.Length() - iDict->At(ii).iData.Length() - found; |
|
589 if (right > 1) |
|
590 { |
|
591 TPtrC8 rt = aMatch.Right(right); |
|
592 FindEmbeddedDict(rt, ii); |
|
593 } |
|
594 break; |
|
595 } |
|
596 } |
|
597 } |
|
598 |
|
599 |
|
600 TPtrC8 CResComp::Resource(TInt aRes) |
|
601 { |
|
602 return TPtrC8(iResData+iResIndex[aRes], iResIndex[aRes+1] - iResIndex[aRes]); |
|
603 } |
|
604 |
|
605 |
|
606 TInt CResComp::FindInResources(TDesC8& aBuf, TInt aMax) |
|
607 { |
|
608 TInt result = KErrNotFound; |
|
609 for (TInt ii=0; ii<aMax; ii++) |
|
610 { |
|
611 TPtrC8 res = Resource(ii); |
|
612 TInt found = res.Find(aBuf); |
|
613 if (found != KErrNotFound) |
|
614 return ii; |
|
615 } |
|
616 return result; |
|
617 } |
|
618 |
|
619 |
|
620 |
|
621 |
|
622 void CResComp::WriteHeaderL(RWriteStream& aStream) |
|
623 { |
|
624 // Write resource header |
|
625 |
|
626 aStream.WriteInt16L(4); // position of dictionary data |
|
627 aStream.WriteInt16L(iResources); |
|
628 } |
|
629 |
|
630 |
|
631 void CResComp::WriteDictionaryL(RWriteStream& aStream) |
|
632 { |
|
633 WriteDictionaryHeaderL(aStream); |
|
634 WriteDictionaryIndexL(aStream); |
|
635 WriteDictionaryDataL(aStream); |
|
636 } |
|
637 |
|
638 void CResComp::WriteDictionaryHeaderL(RWriteStream& aStream) |
|
639 { |
|
640 /* Dictionary header format |
|
641 |
|
642 Offset Length(bytes) Data |
|
643 0 1 Version number |
|
644 1 1 Number of dictionary items |
|
645 2 2 File offset of resource index |
|
646 4 2 Size of largest resource |
|
647 |
|
648 // 2 2 File offset of dictionary |
|
649 // 6 2 File offset of resource data |
|
650 */ |
|
651 aStream.WriteUint8L(1); // used to define different compression methods |
|
652 TInt dictSize = iDict->Count(); |
|
653 TInt diff = (1 << iBitsForDict) - dictSize; |
|
654 aStream.WriteUint8L(diff); |
|
655 TInt headerSize = 4 + 7; |
|
656 TInt resourceIndex = headerSize + iDict->DictionarySize(); |
|
657 // TInt resourceData = resourceIndex + (iResources * 2); |
|
658 aStream.WriteUint16L(resourceIndex); |
|
659 aStream.WriteUint16L(iLargestResourceSize); |
|
660 // RDebug::Print(_L("ResourceIndex:%d bytes"), resourceIndex); |
|
661 aStream.WriteUint8L(iBitsForDict); |
|
662 } |
|
663 |
|
664 void CResComp::WriteDictionaryIndexL(RWriteStream& aStream) |
|
665 { |
|
666 // Write bitIndex of each dictionary element |
|
667 // (as offset from start of dictionaryData) |
|
668 TInt dSize = iDict->Count(); |
|
669 TInt offset = 0; |
|
670 aStream.WriteUint16L(0); |
|
671 for (TInt ii=0; ii<dSize; ii++) |
|
672 { |
|
673 offset += iDict->BitSize(ii); |
|
674 aStream.WriteUint16L(offset); |
|
675 } |
|
676 } |
|
677 |
|
678 void CResComp::WriteDictionaryDataL(RWriteStream& aStream) |
|
679 { |
|
680 TBitWriter bitWrite(aStream); |
|
681 TInt dSize = iDict->Count(); |
|
682 for (TInt ii=0; ii<dSize; ii++) |
|
683 { |
|
684 iDict->WriteBitStreamL(ii, bitWrite); |
|
685 } |
|
686 bitWrite.FlushL(); |
|
687 } |
|
688 |
|
689 |
|
690 |
|
691 void CResComp::WriteResourceL(RWriteStream& aStream) |
|
692 { |
|
693 WriteResourceIndexL(aStream); |
|
694 WriteResourceDataL(aStream); |
|
695 } |
|
696 |
|
697 void CResComp::WriteResourceIndexL(RWriteStream& aStream) |
|
698 { |
|
699 // Write bitIndex of each resource element |
|
700 // (as offset from start of resource Index) |
|
701 TInt offset = 0; |
|
702 aStream.WriteUint16L(0); |
|
703 for (TInt ii=0; ii<iResources; ii++) |
|
704 { |
|
705 offset += ((iResArray->At(ii))->Size(iBitsForDict)); |
|
706 aStream.WriteUint16L(offset); |
|
707 } |
|
708 } |
|
709 |
|
710 void CResComp::WriteResourceDataL(RWriteStream& aStream) |
|
711 { |
|
712 // RDebug::Print(_L("Writing Resource Data")); |
|
713 TBitWriter bitWrite(aStream); |
|
714 for (TInt ii=0; ii<iResources; ii++) |
|
715 { |
|
716 // RDebug::Print(_L("Writing Resource %d"), ii); |
|
717 (iResArray->At(ii))->WriteBitStreamL(bitWrite,iBitsForDict); |
|
718 } |
|
719 bitWrite.FlushL(); |
|
720 } |
|
721 |
|
722 |
|
723 |
|
724 TInt CResComp::OriginalFileSize() |
|
725 { |
|
726 if(iOriginalCompressedSize) |
|
727 return iOriginalCompressedSize; |
|
728 else |
|
729 return iFileLength; |
|
730 } |
|
731 |
|
732 TInt CResComp::CompressedSize() |
|
733 { |
|
734 return iCompressedSize; |
|
735 } |
|
736 |
|
737 void CResComp::DisplayStats() |
|
738 { |
|
739 TInt size = 0; |
|
740 TInt rsize = 0; |
|
741 TInt count = iResArray->Count(); |
|
742 |
|
743 for (TInt jj=0; jj<count; jj++) |
|
744 { |
|
745 rsize += ((iResArray->At(jj))->Size(iBitsForDict));// + 7) / 8; |
|
746 } |
|
747 |
|
748 rsize = (rsize + 7) / 8; |
|
749 |
|
750 size += 4; // res header |
|
751 size += 7; // dict header |
|
752 size += (count + 1) * 2; // res index |
|
753 |
|
754 size += rsize; |
|
755 TInt dSize = iDict->DictionarySize(); |
|
756 |
|
757 // iConsole->Printf(_L("Original Size: %d bytes\n"), iFileLength); |
|
758 // iConsole->Printf(_L("Compressed Resource Size: %d bytes\n"), size); |
|
759 // iConsole->Printf(_L("Compressed Dictionary Size: %d bytes\n"), dSize); |
|
760 // iConsole->Printf(_L("Compressed Size: %d bytes\n"), size+dSize); |
|
761 // iConsole->Printf(_L("Dictionary Size: %d \n"), iDict->Count()); |
|
762 |
|
763 TInt compression = ((size + dSize) * 100) / iFileLength; |
|
764 // iConsole->Printf(_L("Compression = %d %%\n"), compression); |
|
765 |
|
766 |
|
767 iConsole->Printf(_L("\t%d\t%d\t%d\t%d %%\t%d\n"), iFileLength, size+dSize, compression,iOriginalCompressedSize, 1<<iBitsForDict); |
|
768 |
|
769 TInt bitsForDictIndex = 0; |
|
770 while ( (1<<bitsForDictIndex) < dSize) |
|
771 { |
|
772 bitsForDictIndex++; |
|
773 } |
|
774 TInt bitsSaved = iDict->Count() * (16 - bitsForDictIndex); |
|
775 bitsSaved = (bitsSaved + 7) / 8; |
|
776 // RDebug::Print(_L("Possible saving for dictionary: %d"), bitsSaved); |
|
777 |
|
778 TInt bitsForResIndex = 0; |
|
779 while ( (1<<bitsForResIndex) < rsize) |
|
780 { |
|
781 bitsForResIndex++; |
|
782 } |
|
783 TInt rbitsSaved = count * (16 - bitsForResIndex); |
|
784 rbitsSaved = (rbitsSaved + 7) / 8; |
|
785 // RDebug::Print(_L("Possible saving for res: %d"), rbitsSaved); |
|
786 |
|
787 // RDebug::Print(_L("Total Compressed Size: %d Possible: %d"), size+dSize, (size+dSize) - (bitsSaved+rbitsSaved)); |
|
788 } |
|
789 |
|
790 |
|
791 |
|
792 // Check that none of the data lengths exceed 256 bytes. |
|
793 |
|
794 void CResComp::CheckForLongDataStringsL() |
|
795 { |
|
796 RDebug::Print(_L("CheckingForLongDataStrings")); |
|
797 for (TInt ii=0; ii<iResources; ii++) |
|
798 { |
|
799 RDebug::Print(_L("Checking Resource %d"), ii); |
|
800 (iResArray->At(ii))->CheckForLongDataStringsL(); |
|
801 } |
|
802 } |