diff -r 000000000000 -r 044383f39525 bintools/rcomp/src/RCBINSTR.CPP --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bintools/rcomp/src/RCBINSTR.CPP Tue Oct 27 16:36:35 2009 +0000 @@ -0,0 +1,539 @@ +/* +* Copyright (c) 1997-2009 Nokia Corporation and/or its subsidiary(-ies). +* All rights reserved. +* This component and the accompanying materials are made available +* under the terms of the License "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 +#include +#include "ASTRING.H" +#include +#include + +#include "RCBINSTR.H" +#include "TOKENS.H" +#include "STACK.H" +#include "NUMVAL.H" +#include "DATATYPE.H" + +#if defined(__MSVCDOTNET__) || defined(__TOOLS2__) +using std::ofstream; +using std::ios; +#endif //__MSVCDOTNET__ + +extern long CurrentId; +extern RCTypeArray gTypes; + +RCBinaryStream::RCBinaryStream() + {} + +RCBinaryStream::~RCBinaryStream() + { + if (iOs.is_open()) + { + iOs.flush(); + iOs.close(); + } + } + +void RCBinaryStream::OpenForAppend(const String& FileName) + { + assert( !IsOpen()); + + iOs.open( FileName.GetAssertedNonEmptyBuffer(), ios::in | ios::out | ios::binary | ios::ate); // ios::in to prevent overwriting + } + +int RCBinaryStream::IsOpen() + { + return(iOs.is_open()); + } + +RCBinaryStream & RCBinaryStream::operator<< ( char o) + { + Write((const unsigned char*)&o, 1); + return * this; + } + +RCBinaryStream & RCBinaryStream::operator<< ( char * o) + { + Write((const unsigned char*)o, strlen(o)); + return * this; + } + +int RCBinaryStream::SizeOfCompressedInteger(unsigned int aInteger) + { // static + assert((aInteger&~0x7fff)==0); + return (aInteger&~0x7f)? 2: 1; + } + +void RCBinaryStream::WriteCompressedInteger(unsigned int aInteger) + { + assert((aInteger&~0x7fff)==0); + if (aInteger&~0x7f) + { + *this << char((aInteger>>8)|0x80); + } + *this << char(aInteger&0xff); + } + +void RCBinaryStream::Write( const unsigned char * p, unsigned long count) + { + iOs.write( (const char*)p, count); +#if defined(_DEBUG) + iOs.flush(); +#endif + } + +unsigned long RCBinaryStream::GetPosition() + { + return iOs.tellp(); + } + +void RCBinaryStream::SetPosition(unsigned long aNewPosition) + { + assert(aNewPosition<=GetPosition()); + iOs.seekp(aNewPosition, ios::beg); + } + +// ResourceDataStream - this code makes the apparently valid assumption that the decompressing of compressed Unicode (done by BAFL) will yield exactly the same length of string as what you started with before it was compressed (by RCOMP) + +ResourceDataStream::ResourceDataStream() + :iBuffer(NULL), + iNumberOfBytesAllocated(0), + iNumberOfBytesUsed(0), + iContainsCompressedUnicode(false) + { + } + +ResourceDataStream::~ResourceDataStream() + { + delete [] iBuffer; + } + +void ResourceDataStream::StartOfBlockWithSizePrefix(DataType aDataTypeOfSizePrefix) + { + NumericValue* const sizeOfBlockWhenUncompressed=new NumericValue(aDataTypeOfSizePrefix); + assert(sizeOfBlockWhenUncompressed!=NULL); + iArrayOfMarks.AppendMark(iNumberOfBytesUsed, EMarkType_StartOfBlockWithSizePrefix, (unsigned int)sizeOfBlockWhenUncompressed); + } + +void ResourceDataStream::EndOfBlockWithSizePrefix() + { + iArrayOfMarks.AppendMark(iNumberOfBytesUsed, EMarkType_EndOfBlockWithSizePrefix); + } + +void ResourceDataStream::StartOfCompressedUnicodeRun(int aUncompressedUnicodeSizeInBytes, const unsigned char* aUncompressedUnicodeBuffer) + { + if (!iContainsCompressedUnicode) + { + // the first run *must* be a compressed Unicode run, so if it isn't, insert a zero-length one at the start + bool insertZeroLengthCompressedUnicodeRunAtStart=(iNumberOfBytesUsed>0); + if (!insertZeroLengthCompressedUnicodeRunAtStart) + { + const int numberOfMarks=iArrayOfMarks.Size(); + for (int i=0; i0, and we only execute this code if !insertZeroLengthCompressedUnicodeRunAtStart, i.e. if iNumberOfBytesUsed==0 (well, strictly speaking, if iNumberOfBytesUsed<=0) + if (mark.iMarkType==EMarkType_StartOfBlockWithSizePrefix) + { + insertZeroLengthCompressedUnicodeRunAtStart=true; + break; + } + } + } + if (insertZeroLengthCompressedUnicodeRunAtStart) + { + iArrayOfMarks.InsertMark(0, 0, EMarkType_StartOfCompressedUnicodeRun, (unsigned int)BinaryBuffer::New(0, NULL)); // mark the insertion point for the initial zero-length compressed-Unicode run + iArrayOfMarks.InsertMark(1, 0, EMarkType_EndOfCompressedUnicodeRun); // mark the insertion point for the subsquent run of "other stuff" + } + } + iArrayOfMarks.AppendMark(iNumberOfBytesUsed, EMarkType_StartOfCompressedUnicodeRun, (unsigned int)BinaryBuffer::New(aUncompressedUnicodeSizeInBytes, aUncompressedUnicodeBuffer)); + iContainsCompressedUnicode=true; + } + +void ResourceDataStream::EndOfCompressedUnicodeRun() + { +#if !defined(NDEBUG) + const Mark& markAtStartOfCompressedUnicodeRun=iArrayOfMarks.MarkAt(iArrayOfMarks.Size()-1); + assert(markAtStartOfCompressedUnicodeRun.iMarkType==EMarkType_StartOfCompressedUnicodeRun); + const int numberOfBytesWhenCompressed=iNumberOfBytesUsed-markAtStartOfCompressedUnicodeRun.iBufferPosition; + const BinaryBuffer& runWhenUncompressed=*(const BinaryBuffer*)markAtStartOfCompressedUnicodeRun.iOtherData; + assert(numberOfBytesWhenCompressed(iBuffer), numberOfBytesToFirstMark); + bufferIndex+=numberOfBytesToFirstMark; + } + for (int i=0; iNumericValueType()); + runLength+=sizeOfSizePrefix; + uncompressedSize+=sizeOfSizePrefix; + if (pass==0) + { + sizePrefixStack.Push(uncompressedSize, *(NumericValue*)mark.iOtherData); + } + else if (pass==2) + { + aStream << *sizeOfBlockWhenUncompressed; + delete sizeOfBlockWhenUncompressed; + mark.iOtherData=(unsigned int)(NumericValue*)NULL; + } + } + break; + case EMarkType_EndOfBlockWithSizePrefix: + if (pass==0) + { + SizePrefix* const sizePrefix=sizePrefixStack.Pop(); + assert(sizePrefix!=NULL); + sizePrefix->SizeOfBlockWhenUncompressed()=uncompressedSize-sizePrefix->UncompressedSizeOfResourceUpToStartOfBlock(); + delete sizePrefix; + } + break; + case EMarkType_StartOfCompressedUnicodeRun: + { + assert(runLength>=0); + if (addressToWriteSizeOfCompressedIntegerTo!=NULL) + { + *addressToWriteSizeOfCompressedIntegerTo=runLength; + addressToWriteSizeOfCompressedIntegerTo=NULL; + } + runLength=0; + BinaryBuffer& runWhenUncompressed=*(BinaryBuffer*)mark.iOtherData; + const int numberOfBytesWhenUncompressed=runWhenUncompressed.NumberOfBytes(); + const int numberOfBytesWhenUncompressedIncludingAnyPrecedingPaddingByte=numberOfBytesWhenUncompressed+((uncompressedSize%2!=0)? 1: 0); + assert((numberOfBytesWhenUncompressed>0) || !encounteredCompressedUnicode[pass]); // compressed-Unicode runs are of non-zero size apart from the compulsory initial compressed-Unicode run if the resource does not actually start with compressed Unicode + uncompressedSize+=numberOfBytesWhenUncompressedIncludingAnyPrecedingPaddingByte; + assert(i+10) || !encounteredCompressedUnicode[pass]); // compressed-Unicode runs are of non-zero size apart from the compulsory initial compressed-Unicode run if the resource does not actually start with compressed Unicode + assert((numberOfBytesWhenCompressed0)) + { + numberOfBytesWhenCompressedIncludingRunLengthsEitherSide+=RCBinaryStream::SizeOfCompressedInteger(*lengthOfOtherStuffRun); + } + if (numberOfBytesWhenCompressedIncludingRunLengthsEitherSide>=numberOfBytesWhenUncompressedIncludingAnyPrecedingPaddingByte) // use ">=" rather than just ">" as we want to get rid of any compressed-Unicode runs that don't actually give any benefit, so that if possible we can remove the initial compressed-Unicode run (if it's of zero length and it's the only compressed-Unicode run, in which case it's unnecessary overhead) + { + if (isTheFirstCompressedUnicodeRun && isTheLastCompressedUnicodeRun) // if this is the only compressed-Unicode run... + { + iContainsCompressedUnicode=false; + } + ConvertCompressedRunToUncompressed(i-1); + goto startOfFirstPass; // go back to the start of the first pass again as we need to calculate all the fiddly stuff again, e.g. whether two-byte alignment points need padding bytes, etc. + } + } + } + else + { + assert(pass==2); + runWhenUncompressed.Destroy(); + mark.iOtherData=(unsigned int)(BinaryBuffer*)NULL; + aStream.WriteCompressedInteger(numberOfBytesWhenCompressed); + aStream.Write(reinterpret_cast(iBuffer+bufferIndex), numberOfBytesWhenCompressed); + bufferIndex+=numberOfBytesWhenCompressed; + const unsigned int* const lengthOfOtherStuffRun=&nextMark.iOtherData; + if ((lengthOfLastRun!=lengthOfOtherStuffRun) || (*lengthOfOtherStuffRun>0)) + { + aStream.WriteCompressedInteger(*lengthOfOtherStuffRun); + } + } + encounteredCompressedUnicode[pass]=true; + } + break; + case EMarkType_TwoByteAlignmentPoint: + { + const bool needPaddingByte=(uncompressedSize%2!=0); + if (needPaddingByte) + { + ++runLength; + ++uncompressedSize; + if (pass==2) + { + aStream << (unsigned char)(0xab); + } + } + if (pass==0) + { + mark.iOtherData=needPaddingByte; + } + else + { + assert((mark.iOtherData!=0)==needPaddingByte); + } + } + break; + case EMarkType_EnquireStreamPositionWhenKnown: + if (pass==2) + { + unsigned long& streamPosition=*(unsigned long*)mark.iOtherData; + streamPosition=aStream.GetPosition(); + } + break; + default: + assert(0); + break; + } + const int numberOfBytesToNextMark=NumberOfBytesToNextMark(i); + if (pass==2) + { + aStream.Write(reinterpret_cast(iBuffer+bufferIndex), numberOfBytesToNextMark); + } + runLength+=numberOfBytesToNextMark; + uncompressedSize+=numberOfBytesToNextMark; + bufferIndex+=numberOfBytesToNextMark; + } + if (pass>0) + { + assert(aSizeWhenUncompressed==uncompressedSize); + } + else + { + aSizeWhenUncompressed=uncompressedSize; + lengthOfLastRun=addressToWriteSizeOfCompressedIntegerTo; + } + assert(runLength>=0); + if (addressToWriteSizeOfCompressedIntegerTo!=NULL) + { + *addressToWriteSizeOfCompressedIntegerTo=runLength; + addressToWriteSizeOfCompressedIntegerTo=NULL; + } + runLength=0; + } + } + + assert(encounteredCompressedUnicode[0]==iContainsCompressedUnicode); + assert(encounteredCompressedUnicode[1]==iContainsCompressedUnicode); + assert(encounteredCompressedUnicode[2]==iContainsCompressedUnicode); + return encounteredCompressedUnicode[0]; + } + +void ResourceDataStream::Dump(const char* aDumpFile) const + { + ofstream fileStream; + fileStream.open(aDumpFile, ios::out | ios::binary | ios::trunc); + fileStream.write((const char*)iBuffer, iNumberOfBytesUsed); + fileStream.flush(); + fileStream.close(); + } + +void ResourceDataStream::EnsureEnoughSpareBytes(int aNumberOfBytes) + { + const int numberOfBytesSpare=iNumberOfBytesAllocated-iNumberOfBytesUsed; + assert(numberOfBytesSpare>=0); + if (aNumberOfBytes>numberOfBytesSpare) + { + const int newNumberOfBytesAllocated=iNumberOfBytesAllocated+aNumberOfBytes+16; // 16 is just some extra bytes to stop the heap being thrashed too much + unsigned char* const newBuffer = new unsigned char[newNumberOfBytesAllocated]; + if (iNumberOfBytesUsed>0) + { + memcpy(newBuffer, iBuffer, iNumberOfBytesUsed); + } + delete [] iBuffer; + iNumberOfBytesAllocated=newNumberOfBytesAllocated; + iBuffer=newBuffer; + } + } + +int ResourceDataStream::NumberOfBytesToNextMark(int aMarkIndex) const + { + assert(aMarkIndex>=-1); + assert(aMarkIndex=0) + { + numberOfBytesToNextMark-=iArrayOfMarks.MarkAt(aMarkIndex).iBufferPosition; + } + return numberOfBytesToNextMark; + } + +void ResourceDataStream::ConvertCompressedRunToUncompressed(int aMarkIndexOfStartOfCompressedUnicodeRun) + { + // remove the EMarkType_StartOfCompressedUnicodeRun/EMarkType_EndOfCompressedUnicodeRun mark-pair + Mark* markForStartOfCompressedUnicodeRun=&iArrayOfMarks.MarkAt(aMarkIndexOfStartOfCompressedUnicodeRun); + assert(markForStartOfCompressedUnicodeRun->iMarkType==EMarkType_StartOfCompressedUnicodeRun); + BinaryBuffer& runWhenUncompressed=*(BinaryBuffer*)markForStartOfCompressedUnicodeRun->iOtherData; + markForStartOfCompressedUnicodeRun->iOtherData=(unsigned int)(BinaryBuffer*)NULL; + Mark* markForEndOfCompressedUnicodeRun=&iArrayOfMarks.MarkAt(aMarkIndexOfStartOfCompressedUnicodeRun+1); + assert(markForEndOfCompressedUnicodeRun->iMarkType==EMarkType_EndOfCompressedUnicodeRun); + const int bufferPositionOfStartOfCompressedUnicodeRun=markForStartOfCompressedUnicodeRun->iBufferPosition; + const int bufferPositionOfEndOfCompressedUnicodeRun=markForEndOfCompressedUnicodeRun->iBufferPosition; + const int numberOfBytesWhenCompressed=bufferPositionOfEndOfCompressedUnicodeRun-bufferPositionOfStartOfCompressedUnicodeRun; + iArrayOfMarks.RemoveMark(aMarkIndexOfStartOfCompressedUnicodeRun); // remove the EMarkType_StartOfCompressedUnicodeRun mark + iArrayOfMarks.RemoveMark(aMarkIndexOfStartOfCompressedUnicodeRun); // remove the EMarkType_EndOfCompressedUnicodeRun mark + markForStartOfCompressedUnicodeRun=NULL; // just in case we're tempted to use it again now that it's been removed + markForEndOfCompressedUnicodeRun=NULL; // just in case we're tempted to use it again now that it's been removed + const int numberOfBytesWhenUncompressed=runWhenUncompressed.NumberOfBytes(); + const int numberOfExtraBytes=numberOfBytesWhenUncompressed-numberOfBytesWhenCompressed; + + // insert a EMarkType_TwoByteAlignmentPoint mark if necessary + int startOfMarksToUpdate=aMarkIndexOfStartOfCompressedUnicodeRun; + if (numberOfBytesWhenCompressed==0) + { + assert(numberOfExtraBytes==0); + assert(numberOfBytesWhenUncompressed==0); + assert(aMarkIndexOfStartOfCompressedUnicodeRun==0); + } + else + { + assert(numberOfBytesWhenCompressed>0); + iArrayOfMarks.InsertMark(aMarkIndexOfStartOfCompressedUnicodeRun, bufferPositionOfStartOfCompressedUnicodeRun, EMarkType_TwoByteAlignmentPoint); + ++startOfMarksToUpdate; + assert(startOfMarksToUpdate==aMarkIndexOfStartOfCompressedUnicodeRun+1); + } + + // replace the compressed-Unicode bytes in the buffer with the uncompressed equivalent + if (numberOfExtraBytes==0) + { + assert(numberOfBytesWhenCompressed==0); + assert(numberOfBytesWhenUncompressed==0); + assert(aMarkIndexOfStartOfCompressedUnicodeRun==0); + } + else + { + assert(numberOfExtraBytes>0); + + // make room in the buffer to insert the uncompressed Unicode (replacing the compressed-Unicode run) + const int numberOfBytesToMove=iNumberOfBytesUsed-bufferPositionOfEndOfCompressedUnicodeRun; // must be done before MakePlaceHolder is called as MakePlaceHolder will increment iNumberOfBytesUsed by numberOfExtraBytes + MakePlaceHolder(numberOfExtraBytes); + unsigned char* basePointer=iBuffer+bufferPositionOfEndOfCompressedUnicodeRun; + memmove(basePointer+numberOfExtraBytes, basePointer, numberOfBytesToMove); // memmove copes with overlapping source and target areas + + // adjust all the subsequent mark's iBufferPositions + for (int i=iArrayOfMarks.Size()-1; i>=startOfMarksToUpdate; --i) + { + iArrayOfMarks.MarkAt(i).iBufferPosition+=numberOfExtraBytes; + } + } + + // copy in the uncompressed Unicode and destroying the old copy + memcpy(iBuffer+bufferPositionOfStartOfCompressedUnicodeRun, runWhenUncompressed.Buffer(), numberOfBytesWhenUncompressed); + runWhenUncompressed.Destroy(); + } + +ResourceDataStream::BinaryBuffer* ResourceDataStream::BinaryBuffer::New(int aNumberOfBytes, const unsigned char* aBuffer) + { // static + BinaryBuffer* const binaryBuffer=(BinaryBuffer*)malloc((size_t)&((BinaryBuffer*)0)->iBuffer[aNumberOfBytes]); + assert(binaryBuffer!=NULL); + binaryBuffer->iNumberOfBytes=aNumberOfBytes; + assert(aNumberOfBytes>=0); + if (aNumberOfBytes>0) + { + assert(aBuffer!=NULL); + memcpy(binaryBuffer->iBuffer, aBuffer, aNumberOfBytes); + } + return binaryBuffer; + } + +void ResourceDataStream::BinaryBuffer::Destroy() + { + free(this); + } +