bintools/rcomp/src/RCBINSTR.CPP
changeset 0 044383f39525
child 590 360bd6b35136
equal deleted inserted replaced
-1:000000000000 0:044383f39525
       
     1 /*
       
     2 * Copyright (c) 1997-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 the License "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 #include <assert.h>
       
    20 #include <string.h>
       
    21 #include "ASTRING.H"
       
    22 #include <stdlib.h>
       
    23 #include <malloc.h>
       
    24 
       
    25 #include "RCBINSTR.H"
       
    26 #include "TOKENS.H"  
       
    27 #include "STACK.H"   
       
    28 #include "NUMVAL.H"  
       
    29 #include "DATATYPE.H"
       
    30 
       
    31 #if defined(__MSVCDOTNET__) || defined(__TOOLS2__)
       
    32 using std::ofstream;
       
    33 using std::ios;
       
    34 #endif //__MSVCDOTNET__
       
    35 
       
    36 extern long CurrentId;
       
    37 extern RCTypeArray gTypes;
       
    38 
       
    39 RCBinaryStream::RCBinaryStream()
       
    40 	{}
       
    41 
       
    42 RCBinaryStream::~RCBinaryStream()
       
    43 	{
       
    44 	if (iOs.is_open())
       
    45 		{
       
    46 		iOs.flush();
       
    47 		iOs.close();
       
    48 		}
       
    49 	}
       
    50 
       
    51 void RCBinaryStream::OpenForAppend(const String& FileName)
       
    52 	{
       
    53 	assert( !IsOpen());
       
    54 	
       
    55 	iOs.open( FileName.GetAssertedNonEmptyBuffer(), ios::in | ios::out | ios::binary | ios::ate); // ios::in to prevent overwriting
       
    56 	}
       
    57 
       
    58 int RCBinaryStream::IsOpen()
       
    59 	{
       
    60 	return(iOs.is_open());
       
    61 	}
       
    62 		
       
    63 RCBinaryStream & RCBinaryStream::operator<< ( char o)
       
    64 	{
       
    65 	Write((const unsigned char*)&o, 1);
       
    66 	return * this;
       
    67 	}
       
    68 
       
    69 RCBinaryStream & RCBinaryStream::operator<< ( char * o)
       
    70 	{
       
    71 	Write((const unsigned char*)o, strlen(o));
       
    72 	return * this;
       
    73 	}
       
    74 
       
    75 int RCBinaryStream::SizeOfCompressedInteger(unsigned int aInteger)
       
    76 	{ // static
       
    77 	assert((aInteger&~0x7fff)==0);
       
    78 	return (aInteger&~0x7f)? 2: 1;
       
    79 	}
       
    80 
       
    81 void RCBinaryStream::WriteCompressedInteger(unsigned int aInteger)
       
    82 	{
       
    83 	assert((aInteger&~0x7fff)==0);
       
    84 	if (aInteger&~0x7f)
       
    85 		{
       
    86 		*this << char((aInteger>>8)|0x80);
       
    87 		}
       
    88 	*this << char(aInteger&0xff);
       
    89 	}
       
    90 
       
    91 void RCBinaryStream::Write( const unsigned char * p, unsigned long count)
       
    92 	{
       
    93 	iOs.write( (const char*)p, count);
       
    94 #if defined(_DEBUG)
       
    95 	iOs.flush();
       
    96 #endif
       
    97 	}
       
    98 
       
    99 unsigned long RCBinaryStream::GetPosition()
       
   100 	{
       
   101 	return iOs.tellp();
       
   102 	}
       
   103 
       
   104 void RCBinaryStream::SetPosition(unsigned long aNewPosition)
       
   105 	{
       
   106 	assert(aNewPosition<=GetPosition());
       
   107 	iOs.seekp(aNewPosition, ios::beg);
       
   108 	}
       
   109 
       
   110 // 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)
       
   111 
       
   112 ResourceDataStream::ResourceDataStream()
       
   113 	:iBuffer(NULL),
       
   114 	 iNumberOfBytesAllocated(0),
       
   115 	 iNumberOfBytesUsed(0),
       
   116 	 iContainsCompressedUnicode(false)
       
   117 	{
       
   118 	}
       
   119 
       
   120 ResourceDataStream::~ResourceDataStream()
       
   121 	{
       
   122 	delete [] iBuffer;
       
   123 	}
       
   124 
       
   125 void ResourceDataStream::StartOfBlockWithSizePrefix(DataType aDataTypeOfSizePrefix)
       
   126 	{
       
   127 	NumericValue* const sizeOfBlockWhenUncompressed=new NumericValue(aDataTypeOfSizePrefix);
       
   128 	assert(sizeOfBlockWhenUncompressed!=NULL);
       
   129 	iArrayOfMarks.AppendMark(iNumberOfBytesUsed, EMarkType_StartOfBlockWithSizePrefix, (unsigned int)sizeOfBlockWhenUncompressed);
       
   130 	}
       
   131 
       
   132 void ResourceDataStream::EndOfBlockWithSizePrefix()
       
   133 	{
       
   134 	iArrayOfMarks.AppendMark(iNumberOfBytesUsed, EMarkType_EndOfBlockWithSizePrefix);
       
   135 	}
       
   136 
       
   137 void ResourceDataStream::StartOfCompressedUnicodeRun(int aUncompressedUnicodeSizeInBytes, const unsigned char* aUncompressedUnicodeBuffer)
       
   138 	{
       
   139 	if (!iContainsCompressedUnicode)
       
   140 		{
       
   141 		// the first run *must* be a compressed Unicode run, so if it isn't, insert a zero-length one at the start
       
   142 		bool insertZeroLengthCompressedUnicodeRunAtStart=(iNumberOfBytesUsed>0);
       
   143 		if (!insertZeroLengthCompressedUnicodeRunAtStart)
       
   144 			{
       
   145 			const int numberOfMarks=iArrayOfMarks.Size();
       
   146 			for (int i=0; i<numberOfMarks; ++i)
       
   147 				{
       
   148 				const Mark& mark=iArrayOfMarks.MarkAt(i);
       
   149 				assert(mark.iBufferPosition==0);
       
   150 				assert(mark.iMarkType!=EMarkType_TwoByteAlignmentPoint); // it is only possible to have a EMarkType_TwoByteAlignmentPoint mark if iNumberOfBytesUsed>0, and we only execute this code if !insertZeroLengthCompressedUnicodeRunAtStart, i.e. if iNumberOfBytesUsed==0 (well, strictly speaking, if iNumberOfBytesUsed<=0)
       
   151 				if (mark.iMarkType==EMarkType_StartOfBlockWithSizePrefix)
       
   152 					{
       
   153 					insertZeroLengthCompressedUnicodeRunAtStart=true;
       
   154 					break;
       
   155 					}
       
   156 				}
       
   157 			}
       
   158 		if (insertZeroLengthCompressedUnicodeRunAtStart)
       
   159 			{
       
   160 			iArrayOfMarks.InsertMark(0, 0, EMarkType_StartOfCompressedUnicodeRun, (unsigned int)BinaryBuffer::New(0, NULL)); // mark the insertion point for the initial zero-length compressed-Unicode run
       
   161 			iArrayOfMarks.InsertMark(1, 0, EMarkType_EndOfCompressedUnicodeRun); // mark the insertion point for the subsquent run of "other stuff"
       
   162 			}
       
   163 		}
       
   164 	iArrayOfMarks.AppendMark(iNumberOfBytesUsed, EMarkType_StartOfCompressedUnicodeRun, (unsigned int)BinaryBuffer::New(aUncompressedUnicodeSizeInBytes, aUncompressedUnicodeBuffer));
       
   165 	iContainsCompressedUnicode=true;
       
   166 	}
       
   167 
       
   168 void ResourceDataStream::EndOfCompressedUnicodeRun()
       
   169 	{
       
   170 #if !defined(NDEBUG)
       
   171 	const Mark& markAtStartOfCompressedUnicodeRun=iArrayOfMarks.MarkAt(iArrayOfMarks.Size()-1);
       
   172 	assert(markAtStartOfCompressedUnicodeRun.iMarkType==EMarkType_StartOfCompressedUnicodeRun);
       
   173 	const int numberOfBytesWhenCompressed=iNumberOfBytesUsed-markAtStartOfCompressedUnicodeRun.iBufferPosition;
       
   174 	const BinaryBuffer& runWhenUncompressed=*(const BinaryBuffer*)markAtStartOfCompressedUnicodeRun.iOtherData;
       
   175 	assert(numberOfBytesWhenCompressed<runWhenUncompressed.NumberOfBytes());
       
   176 #endif
       
   177 	iArrayOfMarks.AppendMark(iNumberOfBytesUsed, EMarkType_EndOfCompressedUnicodeRun);
       
   178 	}
       
   179 
       
   180 void ResourceDataStream::TwoByteAlignmentPoint()
       
   181 	{
       
   182 	iArrayOfMarks.AppendMark(iNumberOfBytesUsed, EMarkType_TwoByteAlignmentPoint);
       
   183 	}
       
   184 
       
   185 void ResourceDataStream::EnquireStreamPositionWhenKnown(unsigned long& aStreamPosition)
       
   186 	{
       
   187 	iArrayOfMarks.AppendMark(iNumberOfBytesUsed, EMarkType_EnquireStreamPositionWhenKnown, (unsigned int)&aStreamPosition);
       
   188 	}
       
   189 
       
   190 void ResourceDataStream::StreamIn(const unsigned char* aBuffer, int aNumberOfBytes)
       
   191 	{
       
   192 	EnsureEnoughSpareBytes(aNumberOfBytes);
       
   193 	memcpy(iBuffer+iNumberOfBytesUsed, aBuffer, aNumberOfBytes);
       
   194 	iNumberOfBytesUsed+=aNumberOfBytes;
       
   195 	}
       
   196 
       
   197 void ResourceDataStream::MakePlaceHolder(int aNumberOfBytes)
       
   198 	{
       
   199 	EnsureEnoughSpareBytes(aNumberOfBytes);
       
   200 	memset(iBuffer+iNumberOfBytesUsed, 0xeb, aNumberOfBytes);
       
   201 	iNumberOfBytesUsed+=aNumberOfBytes;
       
   202 	}
       
   203 
       
   204 class SizePrefix : public StackItem
       
   205 	{
       
   206 public:
       
   207 	inline SizePrefix(int aUncompressedSizeOfResourceUpToStartOfBlock, NumericValue& aSizeOfBlockWhenUncompressed) :iUncompressedSizeOfResourceUpToStartOfBlock(aUncompressedSizeOfResourceUpToStartOfBlock), iSizeOfBlockWhenUncompressed(aSizeOfBlockWhenUncompressed) {}
       
   208 	inline int UncompressedSizeOfResourceUpToStartOfBlock() const {return iUncompressedSizeOfResourceUpToStartOfBlock;}
       
   209 	inline NumericValue& SizeOfBlockWhenUncompressed() const {return iSizeOfBlockWhenUncompressed;}
       
   210 private:
       
   211 	inline void operator=(const SizePrefix&);
       
   212 private:
       
   213 	int iUncompressedSizeOfResourceUpToStartOfBlock;
       
   214 	NumericValue& iSizeOfBlockWhenUncompressed;
       
   215 	};
       
   216 
       
   217 class SizePrefixStack : public Stack
       
   218 	{
       
   219 public:
       
   220 	inline SizePrefixStack() {}
       
   221 	inline void Push(int aUncompressedSizeOfResourceUpToStartOfBlock, NumericValue& aSizeOfBlockWhenUncompressed) {Stack::Push(new SizePrefix(aUncompressedSizeOfResourceUpToStartOfBlock, aSizeOfBlockWhenUncompressed));}
       
   222 	inline SizePrefix* Pop() {return (SizePrefix*)Stack::Pop();}
       
   223 	};
       
   224 
       
   225 bool ResourceDataStream::StreamOutReturningWhetherContainsCompressedUnicode(RCBinaryStream& aStream, int& aSizeWhenUncompressed)
       
   226 	{
       
   227 startOfFirstPass:
       
   228 	bool encounteredCompressedUnicode[3];
       
   229 	encounteredCompressedUnicode[0]=false;
       
   230 	encounteredCompressedUnicode[1]=false;
       
   231 	encounteredCompressedUnicode[2]=false;
       
   232 	{
       
   233 	// do a first pass (i) to calculate run-lengths of the "other-stuff" runs (i.e. the second, fourth, sixth, etc), (ii) to calculate which EMarkType_TwoByteAlignmentPoint marks require a padding byte, and (iii) to calculate the size-prefixes
       
   234 	// do a second pass to see if there are any compressed-Unicode runs that don't actually make the resource smaller (taking into consideration the preceding run-length byte(s) and any trailing run-length byte(s)) - if so, replace the EMarkType_StartOfCompressedUnicodeRun/EMarkType_EndOfCompressedUnicodeRun mark-pair with a single EMarkType_TwoByteAlignmentPoint mark and go right back to the start of the first pass
       
   235 	// do a third and final pass to actually write out the resource data to aStream
       
   236 	const int numberOfMarks=iArrayOfMarks.Size(); // caching this is done *after* the "startOfFirstPass" as ConvertCompressedRunToUncompressed (which is called just before "goto startOfFirstPass") changes the number of items in iArrayOfMarks
       
   237 	const unsigned int* lengthOfLastRun=NULL;
       
   238 	for (int pass=0; pass<3; ++pass)
       
   239 		{
       
   240 		const int numberOfBytesBeforeFirstMark=NumberOfBytesToNextMark(-1);
       
   241 		int runLength=numberOfBytesBeforeFirstMark;
       
   242 		int uncompressedSize=numberOfBytesBeforeFirstMark;
       
   243 		unsigned int* addressToWriteSizeOfCompressedIntegerTo=NULL; // used on the first pass
       
   244 		SizePrefixStack sizePrefixStack; // used on the first pass
       
   245 		int bufferIndex=0; // used on the third pass
       
   246 		if (pass==2)
       
   247 			{
       
   248 			const int numberOfBytesToFirstMark=NumberOfBytesToNextMark(-1);
       
   249 			assert(bufferIndex==0);
       
   250 			aStream.Write(reinterpret_cast<unsigned char*>(iBuffer), numberOfBytesToFirstMark);
       
   251 			bufferIndex+=numberOfBytesToFirstMark;
       
   252 			}
       
   253 		for (int i=0; i<numberOfMarks; ++i) // must iterate forwards so that lengthOfLastRun is correctly assigned (after the end of this loop) to point to the iOtherData (i.e. run-length) of the last EMarkType_EndOfCompressedUnicodeRun mark
       
   254 			{
       
   255 			Mark& mark=iArrayOfMarks.MarkAt(i);
       
   256 			switch (mark.iMarkType)
       
   257 				{
       
   258 			case EMarkType_StartOfBlockWithSizePrefix:
       
   259 				{
       
   260 				NumericValue* const sizeOfBlockWhenUncompressed=(NumericValue*)mark.iOtherData;
       
   261 				assert(sizeOfBlockWhenUncompressed!=NULL);
       
   262 				const int sizeOfSizePrefix=gTypes.GetSize(sizeOfBlockWhenUncompressed->NumericValueType());
       
   263 				runLength+=sizeOfSizePrefix;
       
   264 				uncompressedSize+=sizeOfSizePrefix;
       
   265 				if (pass==0)
       
   266 					{
       
   267 					sizePrefixStack.Push(uncompressedSize, *(NumericValue*)mark.iOtherData);
       
   268 					}
       
   269 				else if (pass==2)
       
   270 					{
       
   271 					aStream << *sizeOfBlockWhenUncompressed;
       
   272 					delete sizeOfBlockWhenUncompressed;
       
   273 					mark.iOtherData=(unsigned int)(NumericValue*)NULL;
       
   274 					}
       
   275 				}
       
   276 				break;
       
   277 			case EMarkType_EndOfBlockWithSizePrefix:
       
   278 				if (pass==0)
       
   279 					{
       
   280 					SizePrefix* const sizePrefix=sizePrefixStack.Pop();
       
   281 					assert(sizePrefix!=NULL);
       
   282 					sizePrefix->SizeOfBlockWhenUncompressed()=uncompressedSize-sizePrefix->UncompressedSizeOfResourceUpToStartOfBlock();
       
   283 					delete sizePrefix;
       
   284 					}
       
   285 				break;
       
   286 			case EMarkType_StartOfCompressedUnicodeRun:
       
   287 				{
       
   288 				assert(runLength>=0);
       
   289 				if (addressToWriteSizeOfCompressedIntegerTo!=NULL)
       
   290 					{
       
   291 					*addressToWriteSizeOfCompressedIntegerTo=runLength;
       
   292 					addressToWriteSizeOfCompressedIntegerTo=NULL;
       
   293 					}
       
   294 				runLength=0;
       
   295 				BinaryBuffer& runWhenUncompressed=*(BinaryBuffer*)mark.iOtherData;
       
   296 				const int numberOfBytesWhenUncompressed=runWhenUncompressed.NumberOfBytes();
       
   297 				const int numberOfBytesWhenUncompressedIncludingAnyPrecedingPaddingByte=numberOfBytesWhenUncompressed+((uncompressedSize%2!=0)? 1: 0);
       
   298 				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
       
   299 				uncompressedSize+=numberOfBytesWhenUncompressedIncludingAnyPrecedingPaddingByte;
       
   300 				assert(i+1<numberOfMarks);
       
   301 				++i; // skip a loop iteration - we know that EMarkType_StartOfCompressedUnicodeRun marks are always followed by a EMarkType_EndOfCompressedUnicodeRun mark
       
   302 				Mark& nextMark=iArrayOfMarks.MarkAt(i);
       
   303 				assert(nextMark.iMarkType==EMarkType_EndOfCompressedUnicodeRun);
       
   304 				const int numberOfBytesWhenCompressed=nextMark.iBufferPosition-mark.iBufferPosition;
       
   305 				assert((numberOfBytesWhenCompressed>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
       
   306 				assert((numberOfBytesWhenCompressed<numberOfBytesWhenUncompressed) || ((!encounteredCompressedUnicode[pass]) && (numberOfBytesWhenCompressed==0) && (numberOfBytesWhenUncompressed==0)));
       
   307 				if (pass==0)
       
   308 					{
       
   309 					addressToWriteSizeOfCompressedIntegerTo=&nextMark.iOtherData; // iOtherData in "other-stuff" runs (i.e. the second run, the fourth run, the sixth run, etc) stores the combined size of the run taking into account any extra bytes caused by other marks, e.g. a padding byte caused by a ETwoByteAlignmentPoint
       
   310 					}
       
   311 				else if (pass==1)
       
   312 					{
       
   313 					const unsigned int* const lengthOfOtherStuffRun=&nextMark.iOtherData;
       
   314 					const bool isTheFirstCompressedUnicodeRun=!encounteredCompressedUnicode[pass];
       
   315 					const bool isTheLastCompressedUnicodeRun=(lengthOfLastRun==lengthOfOtherStuffRun);
       
   316 					if (isTheLastCompressedUnicodeRun || !isTheFirstCompressedUnicodeRun) // if this is the first compressed-Unicode run and there are others, then we can't get rid of it, hence this check
       
   317 						{
       
   318 						int numberOfBytesWhenCompressedIncludingRunLengthsEitherSide=RCBinaryStream::SizeOfCompressedInteger(numberOfBytesWhenCompressed)+numberOfBytesWhenCompressed;
       
   319 						if ((lengthOfLastRun!=lengthOfOtherStuffRun) || (*lengthOfOtherStuffRun>0))
       
   320 							{
       
   321 							numberOfBytesWhenCompressedIncludingRunLengthsEitherSide+=RCBinaryStream::SizeOfCompressedInteger(*lengthOfOtherStuffRun);
       
   322 							}
       
   323 						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)
       
   324 							{
       
   325 							if (isTheFirstCompressedUnicodeRun && isTheLastCompressedUnicodeRun) // if this is the only compressed-Unicode run...
       
   326 								{
       
   327 								iContainsCompressedUnicode=false;
       
   328 								}
       
   329 							ConvertCompressedRunToUncompressed(i-1);
       
   330 							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.
       
   331 							}
       
   332 						}
       
   333 					}
       
   334 				else
       
   335 					{
       
   336 					assert(pass==2);
       
   337 					runWhenUncompressed.Destroy();
       
   338 					mark.iOtherData=(unsigned int)(BinaryBuffer*)NULL;
       
   339 					aStream.WriteCompressedInteger(numberOfBytesWhenCompressed);
       
   340 					aStream.Write(reinterpret_cast<unsigned char*>(iBuffer+bufferIndex), numberOfBytesWhenCompressed);
       
   341 					bufferIndex+=numberOfBytesWhenCompressed;
       
   342 					const unsigned int* const lengthOfOtherStuffRun=&nextMark.iOtherData;
       
   343 					if ((lengthOfLastRun!=lengthOfOtherStuffRun) || (*lengthOfOtherStuffRun>0))
       
   344 						{
       
   345 						aStream.WriteCompressedInteger(*lengthOfOtherStuffRun);
       
   346 						}
       
   347 					}
       
   348 				encounteredCompressedUnicode[pass]=true;
       
   349 				}
       
   350 				break;
       
   351 			case EMarkType_TwoByteAlignmentPoint:
       
   352 				{
       
   353 				const bool needPaddingByte=(uncompressedSize%2!=0);
       
   354 				if (needPaddingByte)
       
   355 					{
       
   356 					++runLength;
       
   357 					++uncompressedSize;
       
   358 					if (pass==2)
       
   359 						{
       
   360 						aStream << (unsigned char)(0xab);
       
   361 						}
       
   362 					}
       
   363 				if (pass==0)
       
   364 					{
       
   365 					mark.iOtherData=needPaddingByte;
       
   366 					}
       
   367 				else
       
   368 					{
       
   369 					assert((mark.iOtherData!=0)==needPaddingByte);
       
   370 					}
       
   371 				}
       
   372 				break;
       
   373 			case EMarkType_EnquireStreamPositionWhenKnown:
       
   374 				if (pass==2)
       
   375 					{
       
   376 					unsigned long& streamPosition=*(unsigned long*)mark.iOtherData;
       
   377 					streamPosition=aStream.GetPosition();
       
   378 					}
       
   379 				break;
       
   380 			default:
       
   381 				assert(0);
       
   382 				break;
       
   383 				}
       
   384 			const int numberOfBytesToNextMark=NumberOfBytesToNextMark(i);
       
   385 			if (pass==2)
       
   386 				{
       
   387 				aStream.Write(reinterpret_cast<unsigned char*>(iBuffer+bufferIndex), numberOfBytesToNextMark);
       
   388 				}
       
   389 			runLength+=numberOfBytesToNextMark;
       
   390 			uncompressedSize+=numberOfBytesToNextMark;
       
   391 			bufferIndex+=numberOfBytesToNextMark;
       
   392 			}
       
   393 		if (pass>0)
       
   394 			{
       
   395 			assert(aSizeWhenUncompressed==uncompressedSize);
       
   396 			}
       
   397 		else
       
   398 			{
       
   399 			aSizeWhenUncompressed=uncompressedSize;
       
   400 			lengthOfLastRun=addressToWriteSizeOfCompressedIntegerTo;
       
   401 			}
       
   402 		assert(runLength>=0);
       
   403 		if (addressToWriteSizeOfCompressedIntegerTo!=NULL)
       
   404 			{
       
   405 			*addressToWriteSizeOfCompressedIntegerTo=runLength;
       
   406 			addressToWriteSizeOfCompressedIntegerTo=NULL;
       
   407 			}
       
   408 		runLength=0;
       
   409 		}
       
   410 	}
       
   411 
       
   412 	assert(encounteredCompressedUnicode[0]==iContainsCompressedUnicode);
       
   413 	assert(encounteredCompressedUnicode[1]==iContainsCompressedUnicode);
       
   414 	assert(encounteredCompressedUnicode[2]==iContainsCompressedUnicode);
       
   415 	return encounteredCompressedUnicode[0];
       
   416 	}
       
   417 
       
   418 void ResourceDataStream::Dump(const char* aDumpFile) const
       
   419 	{
       
   420 	ofstream fileStream;
       
   421 	fileStream.open(aDumpFile, ios::out | ios::binary | ios::trunc);
       
   422 	fileStream.write((const char*)iBuffer, iNumberOfBytesUsed);
       
   423 	fileStream.flush();
       
   424 	fileStream.close();
       
   425 	}
       
   426 
       
   427 void ResourceDataStream::EnsureEnoughSpareBytes(int aNumberOfBytes)
       
   428 	{
       
   429 	const int numberOfBytesSpare=iNumberOfBytesAllocated-iNumberOfBytesUsed;
       
   430 	assert(numberOfBytesSpare>=0);
       
   431 	if (aNumberOfBytes>numberOfBytesSpare)
       
   432 		{
       
   433 		const int newNumberOfBytesAllocated=iNumberOfBytesAllocated+aNumberOfBytes+16; // 16 is just some extra bytes to stop the heap being thrashed too much
       
   434 		unsigned char* const newBuffer = new unsigned char[newNumberOfBytesAllocated];
       
   435 		if (iNumberOfBytesUsed>0)
       
   436 			{
       
   437 			memcpy(newBuffer, iBuffer, iNumberOfBytesUsed);
       
   438 			}
       
   439 		delete [] iBuffer;
       
   440 		iNumberOfBytesAllocated=newNumberOfBytesAllocated;
       
   441 		iBuffer=newBuffer;
       
   442 		}
       
   443 	}
       
   444 
       
   445 int ResourceDataStream::NumberOfBytesToNextMark(int aMarkIndex) const
       
   446 	{
       
   447 	assert(aMarkIndex>=-1);
       
   448 	assert(aMarkIndex<iArrayOfMarks.Size());
       
   449 	int numberOfBytesToNextMark=(aMarkIndex+1<iArrayOfMarks.Size())? iArrayOfMarks.MarkAt(aMarkIndex+1).iBufferPosition: iNumberOfBytesUsed;
       
   450 	if (aMarkIndex>=0)
       
   451 		{
       
   452 		numberOfBytesToNextMark-=iArrayOfMarks.MarkAt(aMarkIndex).iBufferPosition;
       
   453 		}
       
   454 	return numberOfBytesToNextMark;
       
   455 	}
       
   456 
       
   457 void ResourceDataStream::ConvertCompressedRunToUncompressed(int aMarkIndexOfStartOfCompressedUnicodeRun)
       
   458 	{
       
   459 	// remove the EMarkType_StartOfCompressedUnicodeRun/EMarkType_EndOfCompressedUnicodeRun mark-pair
       
   460 	Mark* markForStartOfCompressedUnicodeRun=&iArrayOfMarks.MarkAt(aMarkIndexOfStartOfCompressedUnicodeRun);
       
   461 	assert(markForStartOfCompressedUnicodeRun->iMarkType==EMarkType_StartOfCompressedUnicodeRun);
       
   462 	BinaryBuffer& runWhenUncompressed=*(BinaryBuffer*)markForStartOfCompressedUnicodeRun->iOtherData;
       
   463 	markForStartOfCompressedUnicodeRun->iOtherData=(unsigned int)(BinaryBuffer*)NULL;
       
   464 	Mark* markForEndOfCompressedUnicodeRun=&iArrayOfMarks.MarkAt(aMarkIndexOfStartOfCompressedUnicodeRun+1);
       
   465 	assert(markForEndOfCompressedUnicodeRun->iMarkType==EMarkType_EndOfCompressedUnicodeRun);
       
   466 	const int bufferPositionOfStartOfCompressedUnicodeRun=markForStartOfCompressedUnicodeRun->iBufferPosition;
       
   467 	const int bufferPositionOfEndOfCompressedUnicodeRun=markForEndOfCompressedUnicodeRun->iBufferPosition;
       
   468 	const int numberOfBytesWhenCompressed=bufferPositionOfEndOfCompressedUnicodeRun-bufferPositionOfStartOfCompressedUnicodeRun;
       
   469 	iArrayOfMarks.RemoveMark(aMarkIndexOfStartOfCompressedUnicodeRun); // remove the EMarkType_StartOfCompressedUnicodeRun mark
       
   470 	iArrayOfMarks.RemoveMark(aMarkIndexOfStartOfCompressedUnicodeRun); // remove the EMarkType_EndOfCompressedUnicodeRun mark
       
   471 	markForStartOfCompressedUnicodeRun=NULL; // just in case we're tempted to use it again now that it's been removed
       
   472 	markForEndOfCompressedUnicodeRun=NULL; // just in case we're tempted to use it again now that it's been removed
       
   473 	const int numberOfBytesWhenUncompressed=runWhenUncompressed.NumberOfBytes();
       
   474 	const int numberOfExtraBytes=numberOfBytesWhenUncompressed-numberOfBytesWhenCompressed;
       
   475 
       
   476 	// insert a EMarkType_TwoByteAlignmentPoint mark if necessary
       
   477 	int startOfMarksToUpdate=aMarkIndexOfStartOfCompressedUnicodeRun;
       
   478 	if (numberOfBytesWhenCompressed==0)
       
   479 		{
       
   480 		assert(numberOfExtraBytes==0);
       
   481 		assert(numberOfBytesWhenUncompressed==0);
       
   482 		assert(aMarkIndexOfStartOfCompressedUnicodeRun==0);
       
   483 		}
       
   484 	else
       
   485 		{
       
   486 		assert(numberOfBytesWhenCompressed>0);
       
   487 		iArrayOfMarks.InsertMark(aMarkIndexOfStartOfCompressedUnicodeRun, bufferPositionOfStartOfCompressedUnicodeRun, EMarkType_TwoByteAlignmentPoint);
       
   488 		++startOfMarksToUpdate;
       
   489 		assert(startOfMarksToUpdate==aMarkIndexOfStartOfCompressedUnicodeRun+1);
       
   490 		}
       
   491 
       
   492 	// replace the compressed-Unicode bytes in the buffer with the uncompressed equivalent
       
   493 	if (numberOfExtraBytes==0)
       
   494 		{
       
   495 		assert(numberOfBytesWhenCompressed==0);
       
   496 		assert(numberOfBytesWhenUncompressed==0);
       
   497 		assert(aMarkIndexOfStartOfCompressedUnicodeRun==0);
       
   498 		}
       
   499 	else
       
   500 		{
       
   501 		assert(numberOfExtraBytes>0);
       
   502 
       
   503 		// make room in the buffer to insert the uncompressed Unicode (replacing the compressed-Unicode run)
       
   504 		const int numberOfBytesToMove=iNumberOfBytesUsed-bufferPositionOfEndOfCompressedUnicodeRun; // must be done before MakePlaceHolder is called as MakePlaceHolder will increment iNumberOfBytesUsed by numberOfExtraBytes
       
   505 		MakePlaceHolder(numberOfExtraBytes);
       
   506 		unsigned char* basePointer=iBuffer+bufferPositionOfEndOfCompressedUnicodeRun;
       
   507 		memmove(basePointer+numberOfExtraBytes, basePointer, numberOfBytesToMove); // memmove copes with overlapping source and target areas
       
   508 
       
   509 		// adjust all the subsequent mark's iBufferPositions
       
   510 		for (int i=iArrayOfMarks.Size()-1; i>=startOfMarksToUpdate; --i)
       
   511 			{
       
   512 			iArrayOfMarks.MarkAt(i).iBufferPosition+=numberOfExtraBytes;
       
   513 			}
       
   514 		}
       
   515 
       
   516 	// copy in the uncompressed Unicode and destroying the old copy
       
   517 	memcpy(iBuffer+bufferPositionOfStartOfCompressedUnicodeRun, runWhenUncompressed.Buffer(), numberOfBytesWhenUncompressed);
       
   518 	runWhenUncompressed.Destroy();
       
   519 	}
       
   520 
       
   521 ResourceDataStream::BinaryBuffer* ResourceDataStream::BinaryBuffer::New(int aNumberOfBytes, const unsigned char* aBuffer)
       
   522 	{ // static
       
   523 	BinaryBuffer* const binaryBuffer=(BinaryBuffer*)malloc((size_t)&((BinaryBuffer*)0)->iBuffer[aNumberOfBytes]);
       
   524 	assert(binaryBuffer!=NULL);
       
   525 	binaryBuffer->iNumberOfBytes=aNumberOfBytes;
       
   526 	assert(aNumberOfBytes>=0);
       
   527 	if (aNumberOfBytes>0)
       
   528 		{
       
   529 		assert(aBuffer!=NULL);
       
   530 		memcpy(binaryBuffer->iBuffer, aBuffer, aNumberOfBytes);
       
   531 		}
       
   532 	return binaryBuffer;
       
   533 	}
       
   534 
       
   535 void ResourceDataStream::BinaryBuffer::Destroy()
       
   536 	{
       
   537 	free(this);
       
   538 	}
       
   539