diff -r 000000000000 -r f58d6ec98e88 reszip/src/rescomp.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/reszip/src/rescomp.cpp Thu Dec 17 09:14:18 2009 +0200 @@ -0,0 +1,802 @@ +/* +* Copyright (c) 1997-1999 Nokia Corporation and/or its subsidiary(-ies). +* All rights reserved. +* This component and the accompanying materials are made available +* under the terms of "Eclipse Public License v1.0" +* which accompanies this distribution, and is available +* at the URL "http://www.eclipse.org/legal/epl-v10.html". +* +* Initial Contributors: +* Nokia Corporation - initial contribution. +* +* Contributors: +* +* Description: +* +*/ + + + +#include "rescomp.h" +#include +#include +#include + +#include + +#include "resdict.h" +#include "resentry.h" + +//#define __DEBUG_WRITE_UNCOMPRESSED_BAFL_RESOURCE + +// TBit Writer + +TBitWriter::TBitWriter(RWriteStream& aStream) +:iStream(aStream) + { + iValue = 0; + iBitsWritten = 0; + } + +void TBitWriter::WriteL(TInt aValue, TInt aBits) + { + // 1<< aBits is the max Value; + + __ASSERT_DEBUG((1< aValue, User::Panic(_L("TBitWriter"),KErrOverflow)); + if (aBits + iBitsWritten < 8) + { + // Not enough data to write a byte + iValue += (aValue << iBitsWritten); + iBitsWritten += aBits; + } + else + { + TInt bitsLeft = 8-iBitsWritten; + TInt mask = (1<> bitsLeft; + TInt bits = aBits - bitsLeft; + while (bits > 7) + { + iStream.WriteUint8L(newValue & 0xff); + bits -= 8; + newValue = (newValue >> 8); + } + iValue = newValue; + iBitsWritten=bits; + } + } + +void TBitWriter::FlushL() + { + if (iBitsWritten > 0) + { + iStream.WriteUint8L(iValue); + iValue = 0; + iBitsWritten=0; + } + } + + + + +CResComp::CResComp(CConsoleBase* aConsole) +:iConsole(aConsole) + { + } + +CResComp::~CResComp() + { + if (iResArray) + { + iResArray->ResetAndDestroy(); + } + delete iResArray; + delete iResData; + delete iDict; + } + + +void CResComp::LoadBAFLCompressedFileL(RFs& aFs, const TDesC& aName) + { + + RResourceFile res; + res.OpenL(aFs, aName); + CleanupClosePushL(res); + + // Count resources + TInt count = 0; + +// This code around ConfirmSigniture had to be added because some S60 resources don't seem to have signature and panic. +// See DEF019933 - RResourceFile::ConfirmSignatureL() needs to be more robust + + HBufC8* const resource=res.AllocReadLC(1); + if(resource->Length()==8) // 8 =Sizeof SSigRecord + { + res.ConfirmSignatureL(0); + } + CleanupStack::PopAndDestroy(resource); + + TInt offset = res.Offset(); + while (res.OwnsResourceId(count+offset+1)) + { + count++; + }; + + const TInt KBufferGranularity = 1000; + CBufFlat* buffer = CBufFlat::NewL(KBufferGranularity); + CleanupStack::PushL(buffer); + + CBufFlat* indexbuffer = CBufFlat::NewL(KBufferGranularity); + CleanupStack::PushL(indexbuffer); + + RBufWriteStream stream; + stream.Open(*buffer); + CleanupClosePushL(stream); + + RBufWriteStream indexstream; + indexstream.Open(*indexbuffer); + CleanupClosePushL(indexstream); + + TInt total = 0; + + for (TInt ii=0; iiLength(); + total += len; + stream.WriteL(*data, len); + CleanupStack::PopAndDestroy(); + } + indexstream.WriteUint16L(total+4); + + + indexstream.CommitL(); + CleanupStack::PopAndDestroy(); // close indexstream + + stream.CommitL(); + CleanupStack::PopAndDestroy(); // close stream + + CBufFlat* outputBuffer = CBufFlat::NewL(KBufferGranularity); + CleanupStack::PushL(outputBuffer); + + RBufWriteStream outStream; + outStream.Open(*outputBuffer); + CleanupClosePushL(outStream); + + + outStream.WriteUint16L(total + 4); // 4 byte header + outStream.WriteUint16L(((count+1)*2)+1); + + TPtr8 ptr = buffer->Ptr(0); + outStream.WriteL(ptr.Ptr(), ptr.Length()); + TPtr8 indexptr = indexbuffer->Ptr(0); + outStream.WriteL(indexptr.Ptr(), indexptr.Length()); + outStream.CommitL(); + CleanupStack::PopAndDestroy();// outStream + + +/* DEBUG - OUTPUT UNCOMPRESSED REPRESENTATION TO A FILE - FOR VERIFICATION */ +#ifdef __DEBUG_WRITE_UNCOMPRESSED_BAFL_RESOURCE + { + TFileName newName(aName); + newName.Append(_L(".ER5u")); + + RFileWriteStream outStream; + User::LeaveIfError(outStream.Replace(aFs, newName, EFileWrite)); + CleanupClosePushL(outStream); + + + outStream.WriteUint16L(total + 4); // 4 byte header + outStream.WriteUint16L(((count+1)*2)+1); + + TPtr8 ptr = buffer->Ptr(0); + outStream.WriteL(ptr.Ptr(), ptr.Length()); + TPtr8 indexptr = indexbuffer->Ptr(0); + outStream.WriteL(indexptr.Ptr(), indexptr.Length()); + outStream.CommitL(); + CleanupStack::PopAndDestroy(); // outStream + } +#endif /* END __DEBUG_WRITE_UNCOMPRESSED_BAFL_RESOURCE */ + + iDict = new(ELeave)CDictArray(); + + iFileLength = outputBuffer->Size(); + + iResData = (TUint8*)User::AllocL(iFileLength); + + Mem::Copy(iResData, const_cast(outputBuffer->Ptr(0).Ptr()), iFileLength ); + + CleanupStack::PopAndDestroy(outputBuffer); + + CleanupStack::PopAndDestroy(indexbuffer); + CleanupStack::PopAndDestroy(buffer); + + CleanupStack::PopAndDestroy(); // res + + // Need to keep original size in order to compare with new compression for IsValid() + TEntry entry; + if( aFs.Entry(aName, entry) ==KErrNone) + { + iOriginalCompressedSize = entry.iSize; + } + + } + +TBool CResComp::FileIsBAFLCompressedL(RFs& aFs, const TDesC& aFileName) + { + const TUid KBAFLCompressedFileUid = {0x101f4a6b}; // rcomp unicode compressed + + TEntry entry; + User::LeaveIfError(aFs.Entry(aFileName,entry)); + + return entry.IsUidPresent(KBAFLCompressedFileUid); + } + +void CResComp::LoadFileL(RFs& aFs, const TDesC& aFileName) + { + ASSERT(iDict==NULL); + + TParsePtrC parse(aFileName); + iConOutput.Format(parse.NameAndExt()); + iConOutput.Append(_L("\t")); + if (parse.NameAndExt().Length() < 16) + { + iConOutput.Append(_L("\t")); + } + + if(FileIsBAFLCompressedL(aFs, aFileName)) + { + LoadBAFLCompressedFileL(aFs, aFileName); + } + else + { + LoadUnCompressedFileL(aFs, aFileName); + } + + } + +void CResComp::LoadUnCompressedFileL(RFs& aFs, const TDesC& aFileName) + { + + iDict = new(ELeave)CDictArray(); + + TEntry entry; + User::LeaveIfError( aFs.Entry(aFileName, entry) ); + iFileLength = entry.iSize; + + iResData = (TUint8*)User::AllocL(entry.iSize + 2); // +2 for file size + + RFileReadStream stream; + User::LeaveIfError( stream.Open(aFs, aFileName, EFileRead) ); + CleanupClosePushL(stream); + stream.ReadL(iResData, entry.iSize); + CleanupStack::PopAndDestroy(); // stream + } + + +void CResComp::CompressL() + { + if (iFileLength == 0) + { + iCompressedSize = iFileLength; + return; + } + + TUint16* resData16 = (TUint16*)iResData; + TInt indexOffset = resData16[0]; + TInt indexLength = resData16[1]; + + if (indexOffset == 4) + { + // File is already compressed + iCompressedSize = iFileLength; + return; + } + + if (indexOffset > iFileLength) + { + iCompressedSize = iFileLength; + return; + } + + iResources = (indexLength / 2) - 1; + +// iConsole->Printf(_L("Resources: %d\n"), iResources); + +// iConOutput.AppendFormat(_L("%d\t\t"), iResources); + + + iResIndex = (TUint16*)(iResData + indexOffset); + + + iResArray = new(ELeave)CArrayPtrFlat(10); + + iResIndex[iResources] = (TUint16)(iFileLength-((iResources+1) * 2)); // end of file - index + + // Build dictionary + +// iConsole->Printf(_L("Building Dictionary\n")); + + for (TInt ii=0; ii lineOut(_L("\r")); + lineOut.Append(iConOutput); + lineOut.AppendFormat(_L("%3d / %3d"), ii+1, iResources); + iConsole->Printf(lineOut); +// iConsole->Printf(_L("\r%d / %d"), ii+1, iResources); + CResEntry* rEntry = new(ELeave)CResEntry(iDict); + CleanupStack::PushL(rEntry); + + TInt resSize = iResIndex[ii+1] - iResIndex[ii]; + if (resSize > iLargestResourceSize) + iLargestResourceSize = resSize; + + rEntry->AddPlainDataL(iResData+iResIndex[ii], iResIndex[ii+1] - iResIndex[ii]); + iResArray->AppendL(rEntry); + CleanupStack::Pop(); //rEntry + + + rEntry->MatchSelfL(ii, this); + } + + // Compress using dictionary + + +// iConsole->Printf(_L("\nCompressing\n")); + + CDictArray* backupDict = iDict->DuplicateL(); + CleanupStack::PushL(backupDict); + + AttemptCompressionL(32); + iDict = backupDict->DuplicateL(); + AttemptCompressionL(64); + iDict = backupDict->DuplicateL(); + AttemptCompressionL(128); + iDict = backupDict->DuplicateL(); + AttemptCompressionL(256); + iDict = backupDict->DuplicateL(); + AttemptCompressionL(512); + iDict = backupDict->DuplicateL(); + + + CompressResourcesL(iBestCompression); + + + CleanupStack::PopAndDestroy(); // backupDict + } + +TInt CResComp::AttemptCompressionL(TInt aDictEntries) + { + TInt size = CompressResourcesL(aDictEntries); +// RDebug::Print(_L("Entries: %d Size:%d"), aDictEntries, size); + + TBool valid = IsValid(); + if (!valid) + { + RDebug::Print(_L("Compression Not Valid")); + } + + if ((size < iBestSize || iBestSize == 0) && valid) + { + iBestCompression = aDictEntries; + iBestSize = size; + } + delete iDict; + iDict = NULL; + return size; + } + + +TInt CResComp::CompressResourcesL(TInt aDictEntries) + { + iMaxEntries = aDictEntries; + iBitsForDict = 0; + while ( (1<iDictionaryBits = iBitsForDict; +// RDebug::Print(_L("Entries: %d Bits: %d"), aDictEntries, iBitsForDict); + iResArray->ResetAndDestroy(); + // Reset dictionary count + + TInt dCount = iDict->Count(); + for (TInt ll=0; llAt(ll).iUses = 0; + } + + for (TInt kk=0; kkAddPlainDataL(iResData+iResIndex[kk], iResIndex[kk+1] - iResIndex[kk]); + rEntry->MatchDictL(); + iResArray->AppendL(rEntry); + CleanupStack::Pop(); // rEntry + } + + + // Optimize Dictionary + + OptimizeDict(); + + // Compress using optimized dictionary + + dCount = iDict->Count(); + for (TInt x=0; xAt(x).iUses = 0; + } + + iResArray->ResetAndDestroy(); + for (TInt xx=0; xxAddPlainDataL(iResData+iResIndex[xx], iResIndex[xx+1] - iResIndex[xx]); + rEntry->MatchDictL(); + iResArray->AppendL(rEntry); + CleanupStack::Pop(); // rEntry + } + + + // Make sure that there is no more than 256 data bytes in each resource component + CheckForLongDataStringsL(); + + TInt size = ResourceSize(); + + TInt count = iResArray->Count(); + + size += 4; // res header + size += 7; // dict header + size += (count + 1) * 2; // res index + + TInt dSize = iDict->DictionarySize(); + + iCompressedSize = size+dSize; + return size+dSize; + } + +TInt CResComp::ResourceSize() + { + TInt resSize = 0; + if (!iResArray) + return -1; + TInt count = iResArray->Count(); + for (TInt jj=0; jjAt(jj))->Size(iBitsForDict)); + } + resSize = (resSize + 7) / 8; + return resSize; + } + + + + +TBool CResComp::IsValid() + { + TInt resSize = ResourceSize(); + TInt dSize = iDict->DictionarySizeWithoutIndex(); + + RDebug::Print(_L("Ressize = %D, dsize=%D, compressedsize=%D , fileSize=%D\n"), resSize, dSize, CompressedSize(), OriginalFileSize()); + + if (resSize < 8192 && dSize < 8192 && (CompressedSize() < OriginalFileSize()) && resSize > 0) + { + return ETrue; + } + return EFalse; + } + + + + + + + + +void CResComp::WriteFileL(RFs& aFs, const TDesC& aName) + { + CBufFlat* buffer = CBufFlat::NewL(1024); + CleanupStack::PushL(buffer); + + RBufWriteStream bStream; + bStream.Open(*buffer); + CleanupClosePushL(bStream); + + + RFileWriteStream fStream; + User::LeaveIfError(fStream.Replace(aFs, aName, EFileWrite)); + + WriteHeaderL(fStream); + WriteDictionaryL(fStream); + WriteResourceL(fStream); + + fStream.Close(); + + CleanupStack::PopAndDestroy(2); // bStream, buffer + } + + + +void CResComp::OptimizeDict() + { + // Find referenced dicts + TInt entries = iDict->Count(); + + for (TInt ii=0; ii dc; + dc.Copy(iDict->At(ii).iData); + + FindEmbeddedDict(dc, ii+1); + } + + // Sort dictionary in order of use + + CDictArray* newDict = new(ELeave)CDictArray(); + CleanupStack::PushL(newDict); + + for (TInt jj=0; jjOrderedInsertL(iDict->At(jj)); + } + + TInt newDictEntries = newDict->Count(); + if (newDictEntries > iMaxEntries) + newDictEntries = iMaxEntries; + + iDict->Reset(); + + for (TInt kk=0; kkSizedInsertL(newDict->At(kk)); + } + + CleanupStack::PopAndDestroy(); // newDict + + for (TInt zz=0; zzAt(zz).CreateEmbeddedDict(zz, iDict); + } + } + + +void CResComp::FindEmbeddedDict(TDesC8& aMatch, TInt aStart) + { + TInt entries = iDict->Count(); + for (TInt ii=aStart; iiAt(ii).iData); + if (found != KErrNotFound) + { + // Found embedded dict + iDict->At(ii).iRef++; + if (found > 1) + { + TPtrC8 left = aMatch.Left(found); + FindEmbeddedDict(left, ii); + } + TInt right = aMatch.Length() - iDict->At(ii).iData.Length() - found; + if (right > 1) + { + TPtrC8 rt = aMatch.Right(right); + FindEmbeddedDict(rt, ii); + } + break; + } + } + } + + +TPtrC8 CResComp::Resource(TInt aRes) + { + return TPtrC8(iResData+iResIndex[aRes], iResIndex[aRes+1] - iResIndex[aRes]); + } + + +TInt CResComp::FindInResources(TDesC8& aBuf, TInt aMax) + { + TInt result = KErrNotFound; + for (TInt ii=0; iiCount(); + TInt diff = (1 << iBitsForDict) - dictSize; + aStream.WriteUint8L(diff); + TInt headerSize = 4 + 7; + TInt resourceIndex = headerSize + iDict->DictionarySize(); +// TInt resourceData = resourceIndex + (iResources * 2); + aStream.WriteUint16L(resourceIndex); + aStream.WriteUint16L(iLargestResourceSize); +// RDebug::Print(_L("ResourceIndex:%d bytes"), resourceIndex); + aStream.WriteUint8L(iBitsForDict); + } + +void CResComp::WriteDictionaryIndexL(RWriteStream& aStream) + { + // Write bitIndex of each dictionary element + // (as offset from start of dictionaryData) + TInt dSize = iDict->Count(); + TInt offset = 0; + aStream.WriteUint16L(0); + for (TInt ii=0; iiBitSize(ii); + aStream.WriteUint16L(offset); + } + } + +void CResComp::WriteDictionaryDataL(RWriteStream& aStream) + { + TBitWriter bitWrite(aStream); + TInt dSize = iDict->Count(); + for (TInt ii=0; iiWriteBitStreamL(ii, bitWrite); + } + bitWrite.FlushL(); + } + + + +void CResComp::WriteResourceL(RWriteStream& aStream) + { + WriteResourceIndexL(aStream); + WriteResourceDataL(aStream); + } + +void CResComp::WriteResourceIndexL(RWriteStream& aStream) + { + // Write bitIndex of each resource element + // (as offset from start of resource Index) + TInt offset = 0; + aStream.WriteUint16L(0); + for (TInt ii=0; iiAt(ii))->Size(iBitsForDict)); + aStream.WriteUint16L(offset); + } + } + +void CResComp::WriteResourceDataL(RWriteStream& aStream) + { +// RDebug::Print(_L("Writing Resource Data")); + TBitWriter bitWrite(aStream); + for (TInt ii=0; iiAt(ii))->WriteBitStreamL(bitWrite,iBitsForDict); + } + bitWrite.FlushL(); + } + + + +TInt CResComp::OriginalFileSize() + { + if(iOriginalCompressedSize) + return iOriginalCompressedSize; + else + return iFileLength; + } + +TInt CResComp::CompressedSize() + { + return iCompressedSize; + } + +void CResComp::DisplayStats() + { + TInt size = 0; + TInt rsize = 0; + TInt count = iResArray->Count(); + + for (TInt jj=0; jjAt(jj))->Size(iBitsForDict));// + 7) / 8; + } + + rsize = (rsize + 7) / 8; + + size += 4; // res header + size += 7; // dict header + size += (count + 1) * 2; // res index + + size += rsize; + TInt dSize = iDict->DictionarySize(); + +// iConsole->Printf(_L("Original Size: %d bytes\n"), iFileLength); +// iConsole->Printf(_L("Compressed Resource Size: %d bytes\n"), size); +// iConsole->Printf(_L("Compressed Dictionary Size: %d bytes\n"), dSize); +// iConsole->Printf(_L("Compressed Size: %d bytes\n"), size+dSize); +// iConsole->Printf(_L("Dictionary Size: %d \n"), iDict->Count()); + + TInt compression = ((size + dSize) * 100) / iFileLength; +// iConsole->Printf(_L("Compression = %d %%\n"), compression); + + + iConsole->Printf(_L("\t%d\t%d\t%d\t%d %%\t%d\n"), iFileLength, size+dSize, compression,iOriginalCompressedSize, 1<Count() * (16 - bitsForDictIndex); + bitsSaved = (bitsSaved + 7) / 8; +// RDebug::Print(_L("Possible saving for dictionary: %d"), bitsSaved); + + TInt bitsForResIndex = 0; + while ( (1<At(ii))->CheckForLongDataStringsL(); + } + }