|
1 /* |
|
2 * Copyright (c) 2007-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 #pragma warning (disable: 4786) |
|
20 |
|
21 // System includes |
|
22 #include <iostream> |
|
23 #include <fstream> |
|
24 |
|
25 // User includes |
|
26 #include "rommanager.h" |
|
27 #include "parameterlist.h" |
|
28 #include "stringutils.h" |
|
29 #include "is_utils.h" |
|
30 |
|
31 // String constants |
|
32 const std::wstring KRomManagerSysBinPath = L"z:\\sys\\bin\\"; |
|
33 const std::string KRomManagerRomDrive = "Z:\\"; |
|
34 const std::string KRomManagerRomLogProcessingFile = "Processing file "; |
|
35 const std::string KRomManagerRomLogReadingResource = "Reading resource "; |
|
36 const std::string KRomManagerRomLogReadingResource2 = " to rom linear address"; |
|
37 const std::string KRomManagerRomLogUids = "Uids: "; |
|
38 const std::string KRomManagerRomLogSecureId = "Secure ID: "; |
|
39 const std::string KRomManagerRomLogVendorId = "Vendor ID: "; |
|
40 const std::string KRomManagerRomLogDeviceFileName = "Device file name: "; |
|
41 |
|
42 |
|
43 RomEntry::RomEntry( const std::string& aSourceLogFile ) |
|
44 : iSourceLogFile( aSourceLogFile ), iSecInfo( 0 ), iUid1( 0 ), iUid2( 0 ), iUid3( 0 ) |
|
45 { |
|
46 iSecInfo = new SBinarySecurityInfo(); |
|
47 iEnvFileName = ""; |
|
48 iRomFileName = ""; |
|
49 } |
|
50 |
|
51 |
|
52 RomEntry::~RomEntry() |
|
53 { |
|
54 delete iSecInfo; |
|
55 } |
|
56 |
|
57 |
|
58 RomManager::RomManager() |
|
59 { |
|
60 } |
|
61 |
|
62 RomManager* RomManager::New( const CParameterList& aParamList ) |
|
63 { |
|
64 RomManager* ret = NULL; |
|
65 |
|
66 // |
|
67 // Are we dealing with a full EPOC32-based environment, i.e. "-z" on the Command Line |
|
68 // or are we working with ROM/ROFSBUILD log files ("-r"). |
|
69 // |
|
70 if ( aParamList.IsFlagSet(CParameterList::EFlagsDisableZDriveChecksSet)) |
|
71 { |
|
72 ret = new RomManagerEmpty(); |
|
73 } |
|
74 else if ( aParamList.RomLogFileNames().size() ) |
|
75 { |
|
76 ret = new RomManagerLogFiles( aParamList.RomLogFileNames() ); |
|
77 } |
|
78 else |
|
79 { |
|
80 ret = new RomManagerFileSystem( aParamList.RomDrivePath() ); |
|
81 } |
|
82 // |
|
83 return ret; |
|
84 } |
|
85 |
|
86 |
|
87 RomManagerFileSystem::RomManagerFileSystem( const std::wstring& aPath ) |
|
88 : iRomPath( aPath ) |
|
89 { |
|
90 } |
|
91 |
|
92 bool RomManagerFileSystem::RomFileExists( const std::wstring& aFileName ) |
|
93 { |
|
94 std::wstring target = std::wstring( aFileName ); |
|
95 ConvertToLocalPath( target, iRomPath ); |
|
96 bool exists = FileExists( target ); |
|
97 return exists; |
|
98 } |
|
99 |
|
100 void RomManagerFileSystem::FindAllAdornedVariants(const std::wstring& aSearchNameWild, std::list<std::wstring>& aAdornedFileNamesFound) |
|
101 { |
|
102 // do nothing |
|
103 } |
|
104 |
|
105 bool RomManagerFileSystem::SidExistsInRom(std::wstring& aFile, TUint32 aSid) |
|
106 { |
|
107 std::wstring romDir(KRomManagerSysBinPath); |
|
108 ConvertToLocalPath( romDir, iRomPath ); |
|
109 |
|
110 // search through the binaries on the ROM drive |
|
111 // to find a matching SID |
|
112 std::list<std::wstring> dirContents; |
|
113 GetDirContents(romDir, dirContents); |
|
114 |
|
115 std::list<std::wstring>::iterator curr = dirContents.begin(); |
|
116 std::list<std::wstring>::iterator end = dirContents.end(); |
|
117 for ( ; curr != end; ++curr ) |
|
118 { |
|
119 std::wstring romFile(KRomManagerSysBinPath); |
|
120 romFile.append(*curr); |
|
121 |
|
122 SBinarySecurityInfo info; |
|
123 ReadSecurityInfo(info,romFile); |
|
124 |
|
125 TUint32 sid = info.iSecureId; |
|
126 |
|
127 if (sid != 0 && sid == aSid) |
|
128 { |
|
129 aFile = KRomManagerSysBinPath + romFile; |
|
130 return true; |
|
131 } |
|
132 } |
|
133 return false; |
|
134 } |
|
135 |
|
136 TInt RomManagerFileSystem::ReadSecurityInfo( SBinarySecurityInfo& aInfo, const std::wstring aFileName ) |
|
137 { |
|
138 // Need to convert the file name to the local path so it can find it |
|
139 std::wstring target = std::wstring( aFileName ); |
|
140 ConvertToLocalPath( target, iRomPath ); |
|
141 return ::ReadSecurityInfo(aInfo,target); |
|
142 } |
|
143 |
|
144 RomManagerLogFiles::RomManagerLogFiles( const std::list<std::wstring>& aLogFileNames ) |
|
145 : iLogFileNames( aLogFileNames ) |
|
146 { |
|
147 for( std::list<std::wstring>::const_iterator it = aLogFileNames.begin() ; it != aLogFileNames.end(); it++ ) |
|
148 { |
|
149 std::string narrowLogFileName = Ucs2ToUtf8( *it ); |
|
150 std::string narrowUpperCaseLogFileName = StringUtils::ToUpper( narrowLogFileName ); |
|
151 |
|
152 // Get the base name |
|
153 int dotPos = narrowUpperCaseLogFileName.find( ".LOG" ); |
|
154 if ( dotPos == std::string::npos ) |
|
155 { |
|
156 } |
|
157 else |
|
158 { |
|
159 const std::string baseName = narrowLogFileName.substr( 0, dotPos ); |
|
160 |
|
161 // Two step process. First, read the log, then, if the log file didn't |
|
162 // contain sufficient meta data (old version of ROFS/ROMBUILD) we resort |
|
163 // to reading a corresponding OBY too (if it exists). |
|
164 const bool needToReadOby = ReadLogFile( narrowLogFileName ); |
|
165 |
|
166 if ( needToReadOby ) |
|
167 { |
|
168 ReadObyFile( baseName + ".OBY" ); |
|
169 } |
|
170 } |
|
171 } |
|
172 } |
|
173 |
|
174 |
|
175 RomManagerLogFiles::~RomManagerLogFiles() |
|
176 { |
|
177 for( RomEntryMap::iterator it=iEntriesIndexedByEnvFileName.begin(); it != iEntriesIndexedByEnvFileName.end(); it++ ) |
|
178 { |
|
179 RomEntry* entry = (*it).second; |
|
180 delete entry; |
|
181 } |
|
182 } |
|
183 |
|
184 |
|
185 bool RomManagerLogFiles::RomFileExists( const std::wstring& aFileName ) |
|
186 { |
|
187 bool exists = false; |
|
188 |
|
189 // Get filename & convert it to uppercase, since our map key is |
|
190 // also in upper case form. |
|
191 std::string narrowFileName = Ucs2ToUtf8( aFileName ); |
|
192 narrowFileName = StringUtils::ToUpper( narrowFileName ); |
|
193 |
|
194 // Do we have a corresponding entry? |
|
195 RomEntry* entry = iEntriesIndexedByRomFileName[ narrowFileName ]; |
|
196 if ( entry != NULL ) |
|
197 { |
|
198 exists = true; |
|
199 } |
|
200 // |
|
201 return exists; |
|
202 } |
|
203 |
|
204 void RomManagerLogFiles::FindAllAdornedVariants(const std::wstring& aSearchNameWild, std::list<std::wstring>& aAdornedFileNamesFound) |
|
205 { |
|
206 RomEntryMap::const_iterator curr = iEntriesIndexedByRomFileName.begin(); |
|
207 RomEntryMap::const_iterator end = iEntriesIndexedByRomFileName.end(); |
|
208 |
|
209 std::wstring searchNameWild = StringUtils::ToUpper(aSearchNameWild); |
|
210 |
|
211 for ( ; curr != end ; ++curr) |
|
212 { |
|
213 std::wstring romFile = Utf8ToUcs2(curr->first); |
|
214 if (StringUtils::WildcardCompare(searchNameWild,romFile)) |
|
215 { |
|
216 aAdornedFileNamesFound.push_back(romFile); |
|
217 } |
|
218 } |
|
219 } |
|
220 |
|
221 bool RomManagerLogFiles::SidExistsInRom(std::wstring& aFile, TUint32 aSid) |
|
222 { |
|
223 RomEntryMap::const_iterator curr = iEntriesIndexedByRomFileName.begin(); |
|
224 RomEntryMap::const_iterator end = iEntriesIndexedByRomFileName.end(); |
|
225 |
|
226 for ( ; curr != end ; ++curr) |
|
227 { |
|
228 RomEntry* romEntry = curr->second; |
|
229 if (romEntry) |
|
230 { |
|
231 if (romEntry->Type() == RomEntry::ETypeBinary) |
|
232 { |
|
233 TUint32 romSid = romEntry->SecurityInfo().iSecureId; |
|
234 if (romSid != 0 && romSid == aSid) |
|
235 { |
|
236 aFile = Utf8ToUcs2(romEntry->RomFileName()); |
|
237 return true; |
|
238 } |
|
239 } |
|
240 } |
|
241 } |
|
242 return false; |
|
243 } |
|
244 |
|
245 TInt RomManagerLogFiles::ReadSecurityInfo( SBinarySecurityInfo& aInfo, const std::wstring aFileName ) |
|
246 { |
|
247 TInt err = -1; |
|
248 |
|
249 // Get filename & convert it to uppercase, since our map key is |
|
250 // also in upper case form. |
|
251 std::string narrowFileName = Ucs2ToUtf8( aFileName ); |
|
252 narrowFileName = StringUtils::ToUpper( narrowFileName ); |
|
253 |
|
254 // Do we have a corresponding entry? |
|
255 RomEntry* entry = iEntriesIndexedByRomFileName[ narrowFileName ]; |
|
256 if ( entry != NULL ) |
|
257 { |
|
258 if ( entry->Type() == RomEntry::ETypeBinary) |
|
259 { |
|
260 aInfo.iSecureId = entry->SecurityInfo().iSecureId; |
|
261 aInfo.iVendorId = entry->SecurityInfo().iVendorId; |
|
262 err = 0; |
|
263 } |
|
264 } |
|
265 // |
|
266 return err; |
|
267 } |
|
268 |
|
269 |
|
270 void RomManagerLogFiles::ReadObyFile( const std::string& aFileName ) |
|
271 { |
|
272 std::wstring fileName = Utf8ToUcs2( aFileName ); |
|
273 if ( FileExists( fileName ) ) |
|
274 { |
|
275 std::ifstream stream; |
|
276 stream.open( aFileName.c_str(), std::ios::binary ); |
|
277 // |
|
278 if ( !stream.fail() ) |
|
279 { |
|
280 try |
|
281 { |
|
282 std::string line; |
|
283 // |
|
284 while( std::getline( stream, line ) ) |
|
285 { |
|
286 line = StringUtils::TrimWhiteSpace( line ); |
|
287 if ( line.length() ) |
|
288 { |
|
289 ProcessObyFileLine( aFileName, line ); |
|
290 } |
|
291 } |
|
292 // |
|
293 stream.close(); |
|
294 } |
|
295 catch( const RomManagerException& e ) |
|
296 { |
|
297 stream.close(); |
|
298 throw e; |
|
299 } |
|
300 } |
|
301 else |
|
302 { |
|
303 throw RomManagerException( RomManagerException::ETypeUnableToOpenCorrespondingOBY, aFileName ); |
|
304 } |
|
305 } |
|
306 else |
|
307 { |
|
308 throw RomManagerException( RomManagerException::ETypeUnableToFindCorrespondingOBY, aFileName ); |
|
309 } |
|
310 } |
|
311 |
|
312 |
|
313 void RomManagerLogFiles::ProcessObyFileLine( const std::string& aFileName, std::string& aLine ) |
|
314 { |
|
315 int breakPos = std::string::npos; |
|
316 RomEntry::TType type = RomEntry::ETypeBinary; |
|
317 // |
|
318 if ( StringUtils::CheckForMatch( "file=", aLine ) ) |
|
319 { |
|
320 breakPos = aLine.find_first_of( "\"" ); |
|
321 type = RomEntry::ETypeBinary; |
|
322 } |
|
323 else if ( StringUtils::CheckForMatch( "data=", aLine ) ) |
|
324 { |
|
325 breakPos = aLine.find_first_of( "\"" ); |
|
326 type = RomEntry::ETypeData; |
|
327 } |
|
328 else if ( StringUtils::CheckForMatch( "extension[", aLine ) ) |
|
329 { |
|
330 // extension[0x0B080004]=\epoc32\release\ARMV5\urel\esound.ldd "Sys\Bin\esound.ldd" |
|
331 const std::string KRemainingExtensionDataText = "0xXXXXXXXX]="; |
|
332 |
|
333 if ( aLine.length() > KRemainingExtensionDataText.length() ) |
|
334 { |
|
335 aLine = aLine.substr( KRemainingExtensionDataText.length() ); |
|
336 breakPos = aLine.find_first_of( "\"" ); |
|
337 } |
|
338 } |
|
339 else if ( StringUtils::CheckForMatch( "primary[", aLine ) ) |
|
340 { |
|
341 // primary[0x0A080004]=\epoc32\release\ARMV5\urel\_ekern.exe "Sys\Bin\ekern.exe" |
|
342 const std::string KRemainingPrimaryDataText = "0xXXXXXXXX]="; |
|
343 |
|
344 if ( aLine.length() > KRemainingPrimaryDataText.length() ) |
|
345 { |
|
346 aLine = aLine.substr( KRemainingPrimaryDataText.length() ); |
|
347 breakPos = aLine.find_first_of( "\"" ); |
|
348 } |
|
349 } |
|
350 else if ( StringUtils::CheckForMatch( "device[", aLine ) ) |
|
351 { |
|
352 // device[0x0C080004]=\epoc32\release\ARMV5\urel\esound.ldd "Sys\Bin\esound.ldd" |
|
353 const std::string KRemainingDeviceDataText = "0xXXXXXXXX]="; |
|
354 |
|
355 if ( aLine.length() > KRemainingDeviceDataText.length() ) |
|
356 { |
|
357 aLine = aLine.substr( KRemainingDeviceDataText.length() ); |
|
358 breakPos = aLine.find_first_of( "\"" ); |
|
359 } |
|
360 } |
|
361 |
|
362 if ( breakPos != std::string::npos ) |
|
363 { |
|
364 // The env file name must be upper case, since our string indicies |
|
365 // require this. |
|
366 std::string envFileName = StringUtils::TrimWhiteSpace( aLine.substr( 0, breakPos ) ); |
|
367 envFileName = StringUtils::ToUpper( envFileName ); |
|
368 |
|
369 std::string romFileName = StringUtils::TrimWhiteSpace( aLine.substr( breakPos ) ); |
|
370 romFileName = KRomManagerRomDrive + romFileName.substr( 1, romFileName.size() - 2 ); |
|
371 |
|
372 // See if we can locate the ROM entry based upon the environment |
|
373 // file name. This should agree with the pre-parsed ROMBUILD/ROFSBUILD |
|
374 // log file that we read prior to this method. |
|
375 RomEntry* file = iEntriesIndexedByEnvFileName[ envFileName ]; |
|
376 |
|
377 // Update the entry with the (presumed missing) 'in-place' Symbian OS |
|
378 // file name. |
|
379 if ( file != NULL ) |
|
380 { |
|
381 romFileName = StringUtils::ToUpper( romFileName ); |
|
382 file->SetRomFileName( romFileName ); |
|
383 |
|
384 // Update type info |
|
385 file->SetType( type ); |
|
386 |
|
387 // ... and make an index entry in the index-by-rom-filename-map |
|
388 iEntriesIndexedByRomFileName[ romFileName ] = file; |
|
389 } |
|
390 } |
|
391 } |
|
392 |
|
393 |
|
394 bool RomManagerLogFiles::ReadLogFile( const std::string& aFileName ) |
|
395 { |
|
396 bool obyParsingRequired = true; |
|
397 std::ifstream stream; |
|
398 stream.open( aFileName.c_str(), std::ios::binary ); |
|
399 |
|
400 if ( !stream.fail() ) |
|
401 { |
|
402 try |
|
403 { |
|
404 std::string line; |
|
405 RomEntry* currentEntry = NULL; |
|
406 // |
|
407 while( std::getline( stream, line ) ) |
|
408 { |
|
409 line = StringUtils::TrimWhiteSpace( line ); |
|
410 if ( line.length() ) |
|
411 { |
|
412 ProcessLogFileLine( line, currentEntry, aFileName, obyParsingRequired ); |
|
413 } |
|
414 } |
|
415 // |
|
416 stream.close(); |
|
417 } |
|
418 catch( const RomManagerException& e ) |
|
419 { |
|
420 stream.close(); |
|
421 throw e; |
|
422 } |
|
423 } |
|
424 else |
|
425 { |
|
426 throw RomManagerException( RomManagerException::ETypeUnableToOpenLogFile, aFileName ); |
|
427 } |
|
428 // |
|
429 return obyParsingRequired; |
|
430 } |
|
431 |
|
432 |
|
433 void RomManagerLogFiles::ProcessLogFileLine( std::string& aLine, RomEntry*& aCurrentEntry, const std::string& aFileName, bool& aObyParsingRequired ) |
|
434 { |
|
435 const bool isBinary = StringUtils::CheckForMatch( KRomManagerRomLogProcessingFile, aLine ); |
|
436 const bool isData = StringUtils::CheckForMatch( KRomManagerRomLogReadingResource, aLine ); |
|
437 // |
|
438 if ( isBinary || isData ) |
|
439 { |
|
440 // Save any existing entry |
|
441 if ( aCurrentEntry != NULL ) |
|
442 { |
|
443 // Env file name |
|
444 iEntriesIndexedByEnvFileName[ aCurrentEntry->EnvFileName() ] = aCurrentEntry; |
|
445 |
|
446 // Rom file name (if set) |
|
447 if ( aCurrentEntry->RomFileName().length() ) |
|
448 { |
|
449 iEntriesIndexedByRomFileName[ aCurrentEntry->RomFileName() ] = aCurrentEntry; |
|
450 } |
|
451 } |
|
452 |
|
453 // If this is a data entry, then we must remove everything after the "to rom linear address" |
|
454 // text, since this is not part of the filename. |
|
455 if ( isData ) |
|
456 { |
|
457 const std::string::size_type linAddrTextPos = aLine.find( KRomManagerRomLogReadingResource2 ); |
|
458 if ( linAddrTextPos != std::string::npos ) |
|
459 { |
|
460 aLine = aLine.substr( 0, linAddrTextPos ); |
|
461 } |
|
462 } |
|
463 |
|
464 // Indicies are upper case file names. |
|
465 aLine = StringUtils::ToUpper( aLine ); |
|
466 |
|
467 // Create a new entry |
|
468 aCurrentEntry = new RomEntry( aFileName ); |
|
469 aCurrentEntry->SetEnvFileName( aLine ); |
|
470 |
|
471 // Set type depending on whether its data or binary |
|
472 if ( isData ) |
|
473 { |
|
474 aCurrentEntry->SetType( RomEntry::ETypeData ); |
|
475 } |
|
476 else if ( isBinary ) |
|
477 { |
|
478 aCurrentEntry->SetType( RomEntry::ETypeBinary ); |
|
479 } |
|
480 } |
|
481 else if ( aCurrentEntry && StringUtils::CheckForMatch( KRomManagerRomLogUids, aLine ) ) |
|
482 { |
|
483 std::istringstream stringStream( aLine ); |
|
484 // |
|
485 TUint32 uid1 = 0; |
|
486 stringStream >> std::hex >> uid1; |
|
487 aCurrentEntry->SetUid1( uid1 ); |
|
488 // |
|
489 TUint32 uid2 = 0; |
|
490 stringStream >> std::hex >> uid2; |
|
491 aCurrentEntry->SetUid2( uid2 ); |
|
492 // |
|
493 TUint32 uid3 = 0; |
|
494 stringStream >> std::hex >> uid3; |
|
495 aCurrentEntry->SetUid3( uid3 ); |
|
496 } |
|
497 else if ( aCurrentEntry && StringUtils::CheckForMatch( KRomManagerRomLogSecureId, aLine ) ) |
|
498 { |
|
499 std::istringstream stringStream( aLine ); |
|
500 // |
|
501 TUint32 sid = 0; |
|
502 stringStream >> std::hex >> sid; |
|
503 aCurrentEntry->SecurityInfo().iSecureId = sid; |
|
504 } |
|
505 else if ( aCurrentEntry && StringUtils::CheckForMatch( KRomManagerRomLogVendorId, aLine ) ) |
|
506 { |
|
507 std::istringstream stringStream( aLine ); |
|
508 // |
|
509 TUint32 vid = 0; |
|
510 stringStream >> std::hex >> vid; |
|
511 aCurrentEntry->SecurityInfo().iVendorId = vid; |
|
512 } |
|
513 else if ( aCurrentEntry && StringUtils::CheckForMatch( KRomManagerRomLogDeviceFileName, aLine ) ) |
|
514 { |
|
515 // Indicies are upper case file names. |
|
516 aLine = StringUtils::ToUpper( KRomManagerRomDrive + aLine ); |
|
517 aCurrentEntry->SetRomFileName( aLine ); |
|
518 |
|
519 // If we see this marker, then ROMBUILD & ROFSBUILD are supplied with the extended |
|
520 // meta data that includes "in-device" file name, hence we don't need to parse |
|
521 // the OBY file in order to obtain this information |
|
522 aObyParsingRequired = false; |
|
523 } |
|
524 } |
|
525 |
|
526 |
|
527 bool RomManagerEmpty::RomFileExists( const std::wstring& aFileName ) |
|
528 { |
|
529 //default return value as there is no Z drive present |
|
530 return false; |
|
531 } |
|
532 |
|
533 TInt RomManagerEmpty::ReadSecurityInfo( SBinarySecurityInfo& aInfo, const std::wstring aFileName ) |
|
534 { |
|
535 // return non zero error value |
|
536 return -1; |
|
537 } |
|
538 |
|
539 void RomManagerEmpty::FindAllAdornedVariants(const std::wstring& aSearchNameWild, std::list<std::wstring>& aAdornedFileNamesFound) |
|
540 { |
|
541 // default return value as there is no Z drive present |
|
542 } |
|
543 |
|
544 bool RomManagerEmpty::SidExistsInRom(std::wstring& aFile, TUint32 aSid) |
|
545 { |
|
546 // default return value as there is no Z drive present |
|
547 return false; |
|
548 } |
|
549 |
|
550 void RomManagerException::Display() const |
|
551 { |
|
552 std::ostringstream stream; |
|
553 stream << "ROM/ROFS OBY/LOG file problem - "; |
|
554 // |
|
555 switch( iType ) |
|
556 { |
|
557 case ETypeUnableToOpenLogFile: |
|
558 stream << "\'" << iFileName << "\'" << " (ROM/ROFSBUILD LOG file) could not be read"; |
|
559 break; |
|
560 case ETypeUnableToOpenCorrespondingOBY: |
|
561 stream << "\'" << iFileName << "\'" << " (ROM/ROFSBUILD OBY file) could not be read"; |
|
562 break; |
|
563 case ETypeUnableToFindCorrespondingOBY: |
|
564 stream << "\'" << iFileName << "\'" << " (ROM/ROFSBUILD OBY file) could not be found"; |
|
565 break; |
|
566 |
|
567 default: |
|
568 stream << "Unknown error"; |
|
569 break; |
|
570 } |
|
571 // |
|
572 stream << std::endl; |
|
573 std::wstring finalMessage = Utf8ToUcs2( stream.str() ); |
|
574 // |
|
575 LERROR( finalMessage ); |
|
576 } |