|
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 <stdlib.h> |
|
21 #include <memory.h> |
|
22 |
|
23 #include "RESOURCE.H" |
|
24 #include "DATATYPE.H" |
|
25 #include "Parser.h" |
|
26 #include "rcomp.hpp" |
|
27 #include "NUMVAL.H" |
|
28 #include "MEM.H" |
|
29 #include "ERRORHAN.H" |
|
30 #include "UNICODE_COMPRESSOR.H" |
|
31 #include "main.h" |
|
32 |
|
33 #if defined(__MSVCDOTNET__) || defined(__TOOLS2__) |
|
34 using std::endl; |
|
35 using std::cout; |
|
36 #endif //__MSVCDOTNET__ |
|
37 |
|
38 extern int verbose; |
|
39 extern String::CharacterSet SourceCharacterSet; |
|
40 |
|
41 void Panic(int aCode) // used by UNICODE_COMPRESSOR.CPP |
|
42 { |
|
43 exit(aCode); |
|
44 } |
|
45 |
|
46 RCTypeArray gTypes; |
|
47 |
|
48 // StructItem based ostream functions |
|
49 |
|
50 ostream& SimpleStructItem::StreamOut ( ostream & os) |
|
51 { |
|
52 return operator<< ( os, * this); |
|
53 } |
|
54 |
|
55 ostream& ArrayStructItem::StreamOut ( ostream & os) |
|
56 { |
|
57 return operator<< ( os, * this); |
|
58 } |
|
59 |
|
60 ostream& StructTypeStructItem::StreamOut ( ostream & os) |
|
61 { |
|
62 return operator<< ( os, * this); |
|
63 } |
|
64 |
|
65 ostream& StructArrayStructItem::StreamOut ( ostream & os) |
|
66 { |
|
67 return operator<< ( os, * this); |
|
68 } |
|
69 |
|
70 ostream& operator<< ( ostream & os, SimpleStructItem & o) |
|
71 { |
|
72 os << "SimpleStructItem "; |
|
73 os << o.iLabel; |
|
74 os << "\t" << gTypes.GetName( o.iItemType); |
|
75 os << "\tDefault: " << o.iDefault; |
|
76 os << "\tLength limit: " << o.iLengthLimit; |
|
77 os << endl; |
|
78 return os ; |
|
79 } |
|
80 |
|
81 ostream& operator<< ( ostream & os, ArrayStructItem & o) |
|
82 { |
|
83 os << "ArrayStructItem "; |
|
84 os << o.iLabel; |
|
85 os << "\t" << gTypes.GetName( o.iItemType); |
|
86 os << "\tDefaults: " << o.iDefaults; |
|
87 os << "\tLen Type: " << ((o.iLenType == 0) ? "<none>" : gTypes.GetName(o.iLenType)); |
|
88 os << "\tSize: " << o.iSize; |
|
89 os << endl; |
|
90 return os ; |
|
91 } |
|
92 |
|
93 ostream& operator<< ( ostream & os, StructTypeStructItem & o) |
|
94 { |
|
95 os << "StructTypeStructItem "; |
|
96 os << o.iLabel; |
|
97 os << endl; |
|
98 return os; |
|
99 } |
|
100 |
|
101 ostream& operator<< ( ostream & os, StructArrayStructItem & o) |
|
102 { |
|
103 os << "StructArrayStructItem "; |
|
104 os << o.iLabel; |
|
105 os << "\tLen Type: " << ( ( o.iLenType == 0) ? "<none>" : gTypes.GetName( o.iLenType) ); |
|
106 os << "\tSize: " << o.iSize; |
|
107 os << endl; |
|
108 return os; |
|
109 } |
|
110 |
|
111 ostream& operator<< ( ostream & os, StructItemArray & o) |
|
112 { |
|
113 if (o.Size() == 0) |
|
114 return ( os << "<none>"); |
|
115 StructItemArrayIterator next(o); |
|
116 StructItem* p; |
|
117 while ((p = next() ) != NULL) |
|
118 p->StreamOut(os); |
|
119 return os; |
|
120 } |
|
121 |
|
122 ostream& operator<< ( ostream & os, StructHeader & o) |
|
123 { |
|
124 os << "StructHeader "; |
|
125 os << o.iLabel << endl; |
|
126 os << "\tLen Type: " << ( ( o.iLenType == 0) ? "<none>" : gTypes.GetName( o.iLenType) ) << endl; |
|
127 os << o.iSIA; |
|
128 return os; |
|
129 } |
|
130 |
|
131 ostream& operator<< ( ostream & os, StructHeaderArray & o) |
|
132 { |
|
133 if (o.Size() == 0) |
|
134 return ( os << "<none>"); |
|
135 StructHeaderArrayIterator next( o); |
|
136 StructHeader* p; |
|
137 while ( ( p = next() ) != NULL) |
|
138 os << *p; |
|
139 return os; |
|
140 } |
|
141 |
|
142 // ResourceItem based ostream functions |
|
143 |
|
144 ostream& SimpleResourceItem::StreamOut(ostream& os) |
|
145 { |
|
146 return operator<<(os,*this); |
|
147 } |
|
148 |
|
149 ostream& ArrayResourceItem::StreamOut(ostream& os) |
|
150 { |
|
151 return operator<<(os,*this); |
|
152 } |
|
153 |
|
154 ostream& StructTypeResourceItem::StreamOut(ostream& os) |
|
155 { |
|
156 return operator<<(os,*this); |
|
157 } |
|
158 |
|
159 ostream& StructArrayResourceItem::StreamOut(ostream& os) |
|
160 { |
|
161 return operator<<(os,*this); |
|
162 } |
|
163 |
|
164 ostream & operator<<(ostream& os,SimpleResourceItem& o) |
|
165 { |
|
166 os << "SimpleResourceItem [" << gTypes.GetName(o.iStructItem->iItemType) << " " << o.iStructItem->iLabel << "] "; |
|
167 switch( o.iStructItem->iItemType) |
|
168 { |
|
169 case L_TEXT: |
|
170 case L_LTEXT: |
|
171 case L_BUF: |
|
172 case L_BYTE: |
|
173 case L_WORD: |
|
174 case L_LONG: |
|
175 os << o.iValue; |
|
176 break; |
|
177 case L_SRLINK: |
|
178 break; // Don't know value yet. |
|
179 } |
|
180 os << endl; |
|
181 return os; |
|
182 } |
|
183 |
|
184 ostream & operator<< ( ostream & os, ArrayResourceItem & o) |
|
185 { |
|
186 os << "ArrayResourceItem [" << o.iStructItem->iLabel << "] "; |
|
187 os << o.iValues; |
|
188 os << endl; |
|
189 return os; |
|
190 } |
|
191 |
|
192 ostream & operator<< ( ostream & os, StructTypeResourceItem & o) |
|
193 { |
|
194 static unsigned long level = 0; // Recursion level. |
|
195 os << "StructTypeResourceItem (Level " << level++ << ") [" << o.iStructItem->iLabel << "] " << endl; |
|
196 os << "----------------------" << endl; |
|
197 os << o.iResourceItems; |
|
198 os << "----------------------" << endl; |
|
199 level--; |
|
200 return os; |
|
201 } |
|
202 |
|
203 ostream & operator<< ( ostream & os, StructArrayResourceItem & o) |
|
204 { |
|
205 static unsigned long level = 0; // Recursion level. |
|
206 os << "StructArrayResourceItem (Level " << level++ << ") [" << o.iStructItem->iLabel << "] " << endl; |
|
207 DataType counttype = o.iStructItem->iLenType; |
|
208 if (counttype==0) |
|
209 counttype = L_WORD; |
|
210 unsigned long nitems = o.iArrayOfResourceItemArrays.Size(); |
|
211 os << "ArrayLength [" << gTypes.GetName(counttype) << "] " << nitems << endl; |
|
212 if (nitems > 0) |
|
213 { |
|
214 os << "----------------------" << endl; |
|
215 os << o.iArrayOfResourceItemArrays; |
|
216 os << "----------------------" << endl; |
|
217 } |
|
218 level--; |
|
219 return os; |
|
220 } |
|
221 |
|
222 ostream & operator<< ( ostream & os, ResourceHeader & o) |
|
223 { |
|
224 os << "ResourceHeader "; |
|
225 os << o.iLabel << endl; |
|
226 os << o.iRIA; |
|
227 return os; |
|
228 } |
|
229 |
|
230 ostream & operator<< ( ostream & os, ResourceItemArray & o) |
|
231 { |
|
232 os << "++ResourceItemArray" << endl; |
|
233 if ( o.iLenType != 0) |
|
234 { |
|
235 os << "LenType: " << gTypes.GetName( o.iLenType) << "\t"; |
|
236 } |
|
237 if ( o.Size() == 0) |
|
238 return ( os << "<none>"); |
|
239 ResourceItemArrayIterator next( o); |
|
240 ResourceItem * p; |
|
241 while ( ( p = next() ) != NULL) |
|
242 p->StreamOut( os); |
|
243 return os; |
|
244 } |
|
245 |
|
246 ostream & operator<< ( ostream & os, ResourceItemArrayArray & o) |
|
247 { |
|
248 os << "--ResourceItemArrayArray" << endl; |
|
249 if ( o.Size() == 0) |
|
250 return ( os << "<none>"); |
|
251 ResourceItemArrayArrayIterator next( o); |
|
252 ResourceItemArray * p; |
|
253 while ( ( p = next() ) != NULL) |
|
254 os << * p; |
|
255 return os; |
|
256 } |
|
257 |
|
258 void StreamOutCompressingIfReducesSize(ResourceDataStream& aStream, const UTF16* aUncompressedUnicodeBuffer, int aUncompressedUnicodeLength) |
|
259 { |
|
260 const int uncompressedUnicodeSizeInBytes = aUncompressedUnicodeLength*2; |
|
261 |
|
262 // |
|
263 // Output buffer allocated to be one byte bigger than uncompressed input buffer. |
|
264 // This is to allow for what appears to be the worst case where the string cannot be |
|
265 // compressed at all. In this case enough memory has to be allocated to contain |
|
266 // the uncompressable string, plus the one-byte compression mode tag. |
|
267 // |
|
268 const int maximumOutputLengthInBytes = uncompressedUnicodeSizeInBytes; |
|
269 unsigned char* const compressedUnicodeBuffer = new unsigned char[maximumOutputLengthInBytes]; |
|
270 assert(compressedUnicodeBuffer != NULL); |
|
271 |
|
272 int compressedUnicodeSizeInBytes; |
|
273 CompressUnicode(compressedUnicodeBuffer, compressedUnicodeSizeInBytes, maximumOutputLengthInBytes, aUncompressedUnicodeBuffer, aUncompressedUnicodeLength); |
|
274 |
|
275 if (compressedUnicodeSizeInBytes < uncompressedUnicodeSizeInBytes) |
|
276 { |
|
277 aStream.StartOfCompressedUnicodeRun(uncompressedUnicodeSizeInBytes, (const unsigned char*)aUncompressedUnicodeBuffer); |
|
278 aStream.StreamIn(compressedUnicodeBuffer, compressedUnicodeSizeInBytes); |
|
279 aStream.EndOfCompressedUnicodeRun(); |
|
280 } |
|
281 else if (uncompressedUnicodeSizeInBytes>0) |
|
282 { |
|
283 aStream.TwoByteAlignmentPoint(); |
|
284 aStream.StreamIn((const unsigned char*)aUncompressedUnicodeBuffer, uncompressedUnicodeSizeInBytes); |
|
285 } |
|
286 |
|
287 delete [] compressedUnicodeBuffer; |
|
288 } |
|
289 |
|
290 // ResourceItem based RCBinaryStream functions |
|
291 // These are used to write the raw data as required in the final output file |
|
292 |
|
293 static void StreamOutSingleValue( |
|
294 ResourceDataStream& aStream, |
|
295 const String & aValue, |
|
296 unsigned long aLinkValue, |
|
297 DataType aItemType, |
|
298 const String * aFileName, |
|
299 int aLineNumber |
|
300 ) |
|
301 { |
|
302 ErrorHandler::Register( aFileName, aLineNumber); // Register in case conversion to number fails. |
|
303 |
|
304 |
|
305 |
|
306 switch ( aItemType) |
|
307 { |
|
308 |
|
309 // 8-bit text |
|
310 |
|
311 case L_TEXT8: |
|
312 { // Null terminator, no leading byte count. |
|
313 unsigned char * p = new unsigned char[ aValue.Length() + 1]; |
|
314 if ( aValue.Length() > 0) |
|
315 memcpy( p, aValue.GetAssertedNonEmptyBuffer(), aValue.Length() ); |
|
316 * ( p + aValue.Length() ) = '\0'; |
|
317 aStream.StreamIn(p, aValue.Length() + 1); |
|
318 delete [] p; |
|
319 break; |
|
320 } |
|
321 case L_LTEXT8: |
|
322 { // Leading byte count, no null terminator. (For zero length string a byte containing |
|
323 // zero is written out. |
|
324 assert ( aValue.Length() <= 255 ); |
|
325 unsigned char * p = new unsigned char[ aValue.Length() + 1]; |
|
326 if ( aValue.Length() > 0) |
|
327 memcpy( p + 1, aValue.GetAssertedNonEmptyBuffer(), aValue.Length() ); |
|
328 *p = (unsigned char)(aValue.Length()); |
|
329 aStream.StreamIn(p, aValue.Length() + 1); |
|
330 delete [] p; |
|
331 break; |
|
332 } |
|
333 case L_BUF8: // Write just the characters from the string. |
|
334 aStream.StreamIn((const unsigned char*)aValue.GetAssertedNonEmptyBuffer(), aValue.Length()); |
|
335 break; |
|
336 |
|
337 |
|
338 // 16-bit text |
|
339 |
|
340 |
|
341 |
|
342 case L_BUF16: // write out unadorned 16-bit characters |
|
343 { |
|
344 int output_count; // used as character count for binary output. |
|
345 |
|
346 // reserve enough for worst case |
|
347 output_count = aValue.Length(); |
|
348 UTF16 *output_buffer = new UTF16[output_count]; |
|
349 |
|
350 aValue.Export(output_buffer, output_count, SourceCharacterSet); |
|
351 |
|
352 // write out the buffer as a stream of octets. |
|
353 #if defined(__TOOLS2_WINDOWS__) |
|
354 StreamOutCompressingIfReducesSize(aStream, (const unsigned short*)output_buffer, output_count); |
|
355 #else |
|
356 StreamOutCompressingIfReducesSize(aStream, output_buffer, output_count); |
|
357 #endif |
|
358 |
|
359 delete [] output_buffer; |
|
360 |
|
361 break; |
|
362 } |
|
363 |
|
364 |
|
365 |
|
366 case L_TEXT16: // write out a null-terminated string |
|
367 // this has no support in BAFL |
|
368 { |
|
369 int output_count; // used as character count for binary output. |
|
370 |
|
371 // reserve enough for worst case + null terminator. |
|
372 output_count = aValue.Length(); |
|
373 UTF16 *output_buffer = new UTF16[output_count +1]; |
|
374 |
|
375 aValue.Export(output_buffer, output_count, SourceCharacterSet); |
|
376 output_buffer[output_count] = 0; |
|
377 output_count +=1; |
|
378 |
|
379 // write out the buffer as a stream of octets. |
|
380 #if defined(__TOOLS2_WINDOWS__) |
|
381 StreamOutCompressingIfReducesSize(aStream, (const unsigned short*)output_buffer, output_count); |
|
382 #else |
|
383 StreamOutCompressingIfReducesSize(aStream, output_buffer, output_count); |
|
384 #endif |
|
385 |
|
386 delete [] output_buffer; |
|
387 |
|
388 break; |
|
389 } |
|
390 |
|
391 |
|
392 case L_LTEXT16: // write out counted string. The count is in |
|
393 // an octet, not a word. |
|
394 |
|
395 { |
|
396 int output_count; // used as character count for binary output. |
|
397 unsigned char lbcount; // To hold the leading byte count. |
|
398 |
|
399 // reserve enough for worst case |
|
400 output_count = aValue.Length(); |
|
401 // XXX I have commented the assert statement below out, because an LTEXT can't have length |
|
402 // XXX bigger than 255, but sometimes this happens. A solution would be to throw an error |
|
403 // XXX in structst.cpp, in the SimpleStructItem::SimpleStructItem() constructor. |
|
404 UTF16 *output_buffer = new UTF16[output_count]; |
|
405 |
|
406 aValue.Export(output_buffer, output_count, SourceCharacterSet); |
|
407 |
|
408 // write out the count. |
|
409 |
|
410 lbcount = (unsigned char) output_count; |
|
411 aStream.StreamIn(&lbcount,1); |
|
412 |
|
413 // write out the buffer as a stream of octets. |
|
414 StreamOutCompressingIfReducesSize(aStream, output_buffer, output_count); |
|
415 |
|
416 delete [] output_buffer; |
|
417 |
|
418 break; |
|
419 } |
|
420 |
|
421 |
|
422 |
|
423 |
|
424 case L_BYTE: |
|
425 case L_WORD: |
|
426 case L_LONG: |
|
427 case L_DOUBLE: |
|
428 assert ( aValue.Length() > 0); |
|
429 if(verbose) { MOFF; cout << "Converting " << aValue << " to number." << endl; MON;} |
|
430 NumericValue( aValue, aItemType).StreamOut(aStream); |
|
431 break; |
|
432 case L_SRLINK: |
|
433 NumericValue( aLinkValue, L_LONG).StreamOut(aStream); |
|
434 break; |
|
435 case L_LINK: |
|
436 case L_LLINK: |
|
437 { |
|
438 if ( aValue.Length() > 0) |
|
439 { |
|
440 DataType dtype = ( aItemType == L_LINK) ? L_WORD : L_LONG; |
|
441 if ( aValue.IsDecNatural() ) // If a resource id was specified explicitly e.g. -75 then output the value. |
|
442 NumericValue(aValue, dtype).StreamOut(aStream); |
|
443 else |
|
444 { |
|
445 // If FindId fails to find the link it will output an |
|
446 // appropriate error and kill the program. |
|
447 ErrorHandler::Register(aFileName, aLineNumber); |
|
448 unsigned long id = pG->ResourceNameIds.FindId(aValue); |
|
449 NumericValue(id, dtype).StreamOut(aStream); |
|
450 } |
|
451 } |
|
452 break; |
|
453 } |
|
454 default: |
|
455 { MOFF; cout << "RCBinaryStream:Unknown type " << gTypes.GetName( aItemType) << endl; MON;} |
|
456 } |
|
457 } |
|
458 |
|
459 void SimpleResourceItem::StreamOut(ResourceDataStream& aStream) const |
|
460 { |
|
461 StreamOutSingleValue(aStream, iValue, iLinkValue, iStructItem->iItemType, iFileName, iLineNumber); |
|
462 } |
|
463 |
|
464 void ArrayResourceItem::StreamOut(ResourceDataStream& aStream) const |
|
465 { |
|
466 NumericValue * itemcount = NULL; |
|
467 if(iStructItem->iSize.Length() == 0) // STRUCT item says [] i.e. no size specified. |
|
468 { |
|
469 if (iStructItem->iLenType == 0) // No LEN declaration so default to WORD. |
|
470 itemcount = new NumericValue( L_WORD); |
|
471 else |
|
472 itemcount = new NumericValue( iStructItem->iLenType); // Use specified type. |
|
473 |
|
474 * itemcount = iValues.Size(); |
|
475 itemcount->StreamOut(aStream); |
|
476 |
|
477 delete itemcount; |
|
478 } |
|
479 if ( iValues.Size() == 0) |
|
480 return; |
|
481 StringArrayIterator next( iValues); |
|
482 String * p; |
|
483 while ( ( p = next() ) != NULL) |
|
484 { |
|
485 assert( iStructItem->iItemType != L_SRLINK); // Can't handle arrays of SRlinks. |
|
486 StreamOutSingleValue(aStream, *p, 0, iStructItem->iItemType, iFileName, iLineNumber); |
|
487 } |
|
488 } |
|
489 |
|
490 void StructTypeResourceItem::StreamOut(ResourceDataStream& aStream) const |
|
491 { |
|
492 iResourceItems.StreamOut(aStream); |
|
493 } |
|
494 |
|
495 void StructArrayResourceItem::StreamOut(ResourceDataStream& aStream) const |
|
496 { |
|
497 NumericValue * itemcount = NULL; |
|
498 if(iStructItem->iLenType == 0) // No LEN declaration so default to WORD. |
|
499 itemcount = new NumericValue( L_WORD); |
|
500 else |
|
501 itemcount = new NumericValue( iStructItem->iLenType); // Use specified type. |
|
502 * itemcount = iArrayOfResourceItemArrays.Size(); |
|
503 itemcount->StreamOut(aStream); |
|
504 delete itemcount; |
|
505 if(iArrayOfResourceItemArrays.Size() == 0) |
|
506 return; |
|
507 iArrayOfResourceItemArrays.StreamOut(aStream); |
|
508 } |
|
509 |
|
510 void ResourceItemArray::StreamOut(ResourceDataStream& aStream) const |
|
511 { |
|
512 if (Size() == 0) |
|
513 return; |
|
514 static unsigned int RecursionLevel = 0; // Top level should not have resource size output. |
|
515 const bool outputSize=((iLenType != 0) && (RecursionLevel > 0)); |
|
516 if (outputSize) |
|
517 { |
|
518 aStream.StartOfBlockWithSizePrefix(iLenType); |
|
519 } |
|
520 RecursionLevel++; |
|
521 ResourceItemArrayIterator next(*this); |
|
522 ResourceItem * p; |
|
523 while ( ( p = next() ) != NULL) |
|
524 { |
|
525 p->StreamOut(aStream); |
|
526 } |
|
527 RecursionLevel--; |
|
528 if (outputSize) |
|
529 { |
|
530 aStream.EndOfBlockWithSizePrefix(); |
|
531 } |
|
532 } |
|
533 |
|
534 void ResourceItemArrayArray::StreamOut(ResourceDataStream& aStream) const |
|
535 { |
|
536 if (Size() == 0) |
|
537 return; |
|
538 ResourceItemArrayArrayIterator next(*this); |
|
539 ResourceItemArray * p; |
|
540 while ( ( p = next() ) != NULL) |
|
541 p->StreamOut(aStream); |
|
542 } |