|
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 |