|
1 // Copyright (c) 1997-2009 Nokia Corporation and/or its subsidiary(-ies). |
|
2 // All rights reserved. |
|
3 // This component and the accompanying materials are made available |
|
4 // under the terms of "Eclipse Public License v1.0" |
|
5 // which accompanies this distribution, and is available |
|
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
7 // |
|
8 // Initial Contributors: |
|
9 // Nokia Corporation - initial contribution. |
|
10 // |
|
11 // Contributors: |
|
12 // |
|
13 // Description: |
|
14 // |
|
15 |
|
16 #if defined(__MSVCDOTNET__) || defined(__TOOLS2__) |
|
17 #include <ostream> |
|
18 #include <iostream> |
|
19 using namespace std; |
|
20 #else //!__MSVCDOTNET__ && !__TOOLS2__ |
|
21 #include <ostream.h> |
|
22 #endif //__MSVCDOTNET__ |
|
23 |
|
24 #include "TOOLSVER.H" |
|
25 #include "BMCONV.H" |
|
26 #include <sys/types.h> |
|
27 #include <sys/stat.h> |
|
28 #include <stdio.h> |
|
29 |
|
30 |
|
31 /** |
|
32 Returns an informative error message, the result of the program actions performed. |
|
33 @return Informative error string |
|
34 @param aErrorNumber The error returned from the actions performed |
|
35 @param aDestfile The multiple bitmap store file name |
|
36 @param aDestCreated True if the multiple bitmap store has been created/modified |
|
37 */ |
|
38 |
|
39 char* ErrorMessage(int aErrorNumber, char* aDestfile=NULL, bool aDestCreated=false) |
|
40 { |
|
41 // Remove the multiple bitmap store if it has been created/modified during an fstream session and there has been an error |
|
42 if(aDestfile && (aErrorNumber != NoError) && (aDestCreated == true)) |
|
43 { |
|
44 remove(aDestfile); |
|
45 } |
|
46 |
|
47 switch(aErrorNumber) |
|
48 { |
|
49 case NoError: |
|
50 return "Success."; |
|
51 case NoMemory: |
|
52 return "Out of memory."; |
|
53 case Arg: |
|
54 return "Bad argument."; |
|
55 case Files: |
|
56 return "File does not exist"; |
|
57 case SourceFile: |
|
58 return "Bad source file(s)."; |
|
59 case DestFile: |
|
60 return "Bad destination file(s)."; |
|
61 case CommandFile: |
|
62 return "Bad command file."; |
|
63 case OutOfRange: |
|
64 return "Number of sources/targets mismatch."; |
|
65 case TooManyArgs: |
|
66 return "Too many arguments."; |
|
67 case UnknownCompression: |
|
68 return "Unknown source compression type."; |
|
69 case CompressionError: |
|
70 return "Compression error."; |
|
71 case DecompressionError: |
|
72 return "Decompression error."; |
|
73 case Bpp: |
|
74 return "Invalid bitmap mode specified."; |
|
75 case PaletteFile: |
|
76 return "Bad palette file."; |
|
77 case PaletteSupportNotImplemented: |
|
78 return "Palettes not supported"; |
|
79 case AlphaFiles: |
|
80 return "Alpha bitmap file does not exist"; |
|
81 case AlphaDimensions: |
|
82 return "Alpha channel bitmap's dimensions don't match pixel bitmap's dimensions."; |
|
83 case AlphaBpp: |
|
84 return "Alpha channel bitmap must be 8bpp."; |
|
85 default: |
|
86 return "Unknown error!"; |
|
87 }; |
|
88 } |
|
89 |
|
90 void Header() |
|
91 { |
|
92 cout << "\n"; |
|
93 cout << "\n"; |
|
94 cout << "BMCONV version "<< version << ".\n"; |
|
95 } |
|
96 |
|
97 void Report(int aError) |
|
98 { |
|
99 Header(); |
|
100 cout << ErrorMessage(aError) << "\n"; |
|
101 } |
|
102 |
|
103 /** |
|
104 Compiliation information to print to the user at the end of the program. |
|
105 @param aQuiet Flag if the user selected quiet output mode |
|
106 @param aError The error returned from the actions performed |
|
107 @param aType The multiple bitmap store type created |
|
108 @param aDestfile The multiple bitmap store file name |
|
109 @param aBitmapFiles The array of bitmaps used |
|
110 @param aNumFiles The amount of bitmaps used |
|
111 @param aDestCreated True if the multiple bitmap store has been created/modified |
|
112 */ |
|
113 |
|
114 void CompilationReport(int aQuiet,int aError,TStoreType aType,char* aDestfile,char** aBitmapFiles,int aNumFiles, bool aDestCreated) |
|
115 { |
|
116 if(!aQuiet || aError) |
|
117 { |
|
118 Header(); |
|
119 cout << "Compiling...\n"; |
|
120 if(aType!=ENoStore) |
|
121 cout << "Multiple bitmap store type: "; |
|
122 if(aType==EFileStore) |
|
123 cout << "File store" << "\n"; |
|
124 else if(aType==ERomStore) |
|
125 cout << "ROM image store" << "\n"; |
|
126 else if(aType==ECompressedRomStore) |
|
127 cout << "Compressed ROM image store" << "\n"; |
|
128 if(aDestfile!=NULL) |
|
129 cout << "Epoc file: " << aDestfile << "\n\n"; |
|
130 for(int count=0;count<aNumFiles;count++) |
|
131 { |
|
132 cout << "Bitmap file " << count+1 << " : "; |
|
133 cout << aBitmapFiles[count] << "\n"; |
|
134 } |
|
135 cout << ErrorMessage(aError, aDestfile, aDestCreated) << "\n"; |
|
136 } |
|
137 } |
|
138 |
|
139 void DecompilationReport(int aError,char* aDestfile,char** aBitmapFiles,int aNumFiles) |
|
140 { |
|
141 Header(); |
|
142 cout << "Decompiling...\n"; |
|
143 if(aDestfile!=NULL) |
|
144 cout << "Epoc file: " << aDestfile << "\n\n"; |
|
145 for(int count=0;count<aNumFiles;count++) |
|
146 { |
|
147 cout << "Bitmap file " << count+1 << " : "; |
|
148 cout << aBitmapFiles[count] << "\n"; |
|
149 } |
|
150 cout << ErrorMessage(aError) << "\n"; |
|
151 } |
|
152 |
|
153 void Usage() |
|
154 { |
|
155 cout << "\n"; |
|
156 cout << "BMCONV version "<< version << ".\n"; |
|
157 cout << "Symbian OS multiple bitmap file/rom store conversion program.\n"; |
|
158 cout << "Copyright (c) 2007 Nokia Corporation and/or its subsidiary(-ies)."; |
|
159 cout << "\n"; |
|
160 cout << "\n"; |
|
161 cout << "Usage:\n"; |
|
162 cout << "BMCONV [-r|-s|-n] [-hfilename] [-q] [-pfilename] epocfile [OPT]bmp_1 ... [OPT]bmp_n\n"; |
|
163 cout << "BMCONV [-r|-s|-n] [-q] [-pfilename] epocfile -mepocfile2\n"; |
|
164 cout << "BMCONV -u epocfile bmp_1 [... bmp_n]\n"; |
|
165 cout << "BMCONV -v epocfile\n"; |
|
166 cout << "BMCONV commandfile\n"; |
|
167 cout << "\n"; |
|
168 cout << " -r specifies a ROM image destination file,\n"; |
|
169 cout << " -s specifies a compressed ROM image file,\n"; |
|
170 cout << " -n disables bitmap File Store compression,\n"; |
|
171 cout << " the default is a compressed File Store file.\n\n"; |
|
172 cout << " -q specifies quiet mode - only errors are reported.\n\n"; |
|
173 cout << " -hfilename specifies the filename for the automatic\n"; |
|
174 cout << " generation of a header file for inclusion into code.\n\n"; |
|
175 cout << " -pfilename gives the filename of a palette file containing 256 hex\n"; |
|
176 cout << " numbers (0x00BBGGRR) specifying the palette for 8bpp colour bitmaps.\n"; |
|
177 cout << " (Omission results in the use of a default palette.)\n\n"; |
|
178 cout << " OPT may be one of -1, -2, -4, -8, -c4, -c8, -c12, -c16, -c24 -c32 -c32a\n"; |
|
179 cout << " specifying bits per pixel and grey-scale-colour, or -mepocfile2\n"; |
|
180 cout << " to specify an existing multiple bitmap file. default is -2.\n\n"; |
|
181 cout << " To avoid ambiguity when specifying -c32 with a bitmap file whose name\n"; |
|
182 cout << " begins with an 'a', use a relative or direct directory reference\n"; |
|
183 cout << " e.g. -c32.\\abitmap.bmp or -c32c:\\abitmap.bmp\n"; |
|
184 cout << " Directory names must not include spaces.\n\n"; |
|
185 cout << " -c32a specifies use of an alpha channel in a 32bpp bitmap. Alpha data\n"; |
|
186 cout << " is supplied in a separate 8bpp bmp file with identical dimensions to\n"; |
|
187 cout << " the pixel data. This file must be named as bmp_n with the suffix '-alpha'\n"; |
|
188 cout << " e.g. if bmp_1 is 'my.bmp' then the file 'my-alpha.bmp' is required in the\n"; |
|
189 cout << " same directory. The alpha file does not need to be specified.\n\n"; |
|
190 cout << " epocfile specifies the epoc multi-bitmap file name.\n"; |
|
191 cout << " bmp_n specifies the nth bitmap file name.\n\n"; |
|
192 cout << " -u decompiles epocfile to bmp_1,...,bmp_n.\n"; |
|
193 cout << " If an alpha channel is present then a further, 8bpp file is output for \n"; |
|
194 cout << " the alpha data, named with an '-alpha' suffix as described above.\n\n"; |
|
195 cout << " -v displays a summary of the bitmaps in epocfile\n"; |
|
196 cout << " otherwise bmp_1,...,bmp_n are compiled to epocfile\n\n"; |
|
197 cout << " commandfile specifies a file containing the commandline\n"; |
|
198 cout << " with commands separated by spaces or newlines.\n\n"; |
|
199 cout << " When bmconv is used on Windows, options may start with '/' or '-'\n"; |
|
200 |
|
201 } |
|
202 |
|
203 int IsWhiteSpace(char aCharacter) |
|
204 { |
|
205 return(aCharacter==' ' || aCharacter=='\n' || aCharacter=='\r' || aCharacter==0x1a); |
|
206 } |
|
207 |
|
208 int ProcessCommandFile(char* aCommandFileName,char** aArgPtrs,int& aNumArgs) |
|
209 { |
|
210 struct stat fileinfo; |
|
211 if (stat(aCommandFileName,&fileinfo)==-1) |
|
212 return CommandFile; |
|
213 |
|
214 int filesize=fileinfo.st_size; |
|
215 if (filesize==0) |
|
216 return NoError; |
|
217 #if defined(__MSVCDOTNET__) || defined(__TOOLS2__) |
|
218 fstream commandfile(aCommandFileName, ios::in | ios::binary); |
|
219 #else //!__MSVCDOTNET__ |
|
220 fstream commandfile(aCommandFileName, ios::in | ios::binary | ios::nocreate); |
|
221 #endif //__MSVCDOTNET__ |
|
222 if(!commandfile.is_open()) |
|
223 return CommandFile; |
|
224 |
|
225 char* commandData=new char[filesize+1]; |
|
226 if(commandData==NULL) |
|
227 return NoMemory; |
|
228 |
|
229 memset(commandData,0,filesize+1); |
|
230 commandfile.read(commandData,filesize); |
|
231 commandData[filesize]='\0'; |
|
232 |
|
233 char* commandptr = (char*)commandData; |
|
234 char* commandptrLimit = (char*)(commandData + filesize); |
|
235 while (commandptr < commandptrLimit) |
|
236 { |
|
237 if(*commandptr=='/' && *(commandptr+1)=='/') |
|
238 while(*commandptr!='\n' && *commandptr!='\r' && commandptr < commandptrLimit) |
|
239 *commandptr++=' '; |
|
240 else if (*commandptr==0x1a) |
|
241 *commandptr++=' '; |
|
242 commandptr++; |
|
243 } |
|
244 |
|
245 commandptr = (char*)commandData; |
|
246 while (commandptr < commandptrLimit) |
|
247 { |
|
248 while(IsWhiteSpace(*commandptr) && commandptr < commandptrLimit) |
|
249 *commandptr++='\0'; |
|
250 if (commandptr == commandptrLimit) |
|
251 break; |
|
252 aArgPtrs[aNumArgs]=commandptr; |
|
253 while(!IsWhiteSpace(*commandptr) && commandptr < commandptrLimit) |
|
254 commandptr++; |
|
255 if (commandptr == commandptrLimit) |
|
256 break; |
|
257 aNumArgs++; |
|
258 } |
|
259 |
|
260 commandfile.close(); |
|
261 return NoError; |
|
262 } |
|
263 |
|
264 int Decompile(int aArgc,int aNumArgs,char** aArgPtrs) |
|
265 { |
|
266 int ret=OutOfRange; |
|
267 char* destfilename=aArgPtrs[1]; |
|
268 |
|
269 if(aArgc>=4 || aArgc==2) |
|
270 { |
|
271 for(int count=2;count<aNumArgs;count++) |
|
272 { |
|
273 EpocLoader pl; |
|
274 ret=pl.LoadEpocBitmap(destfilename,count-2); |
|
275 if(!ret) ret=pl.SaveBitmap(aArgPtrs[count]); |
|
276 if(ret) break; |
|
277 } |
|
278 DecompilationReport(ret,destfilename,&aArgPtrs[2],aNumArgs-2); |
|
279 } |
|
280 else |
|
281 DecompilationReport(ret,NULL,NULL,0); |
|
282 |
|
283 return ret; |
|
284 } |
|
285 |
|
286 int Compile(int aNumArgs,int aArgArraySize, char** aArgPtrs) |
|
287 { |
|
288 TStoreType storeType = EFileStore; |
|
289 int compression = 1; |
|
290 int quiet = 0; |
|
291 char* headerfilename = NULL; |
|
292 char* palettefilename = NULL; |
|
293 char* destfilename = NULL; |
|
294 int ret = OutOfRange; |
|
295 bool aDestCreated = false; |
|
296 |
|
297 for(int argnum=0;argnum<aNumArgs;argnum++) |
|
298 { |
|
299 if(aArgPtrs[argnum] && (aArgPtrs[argnum][0] == OPTCHAR || aArgPtrs[argnum][0]==ALTERNATE_OPTCHAR)) |
|
300 { |
|
301 if(aArgPtrs[argnum][1]=='r' || aArgPtrs[argnum][1]=='R') |
|
302 { |
|
303 if(storeType==ECompressedRomStore) |
|
304 { |
|
305 ret=TooManyArgs; |
|
306 CompilationReport(quiet,ret,storeType,NULL,NULL,0,aDestCreated); |
|
307 return ret; |
|
308 } |
|
309 storeType=ERomStore; |
|
310 aArgPtrs[argnum] = NULL; |
|
311 } |
|
312 else if(aArgPtrs[argnum][1]=='s' || aArgPtrs[argnum][1]=='S') |
|
313 { |
|
314 if(storeType==ERomStore) |
|
315 { |
|
316 ret=TooManyArgs; |
|
317 CompilationReport(quiet,ret,storeType,NULL,NULL,0,aDestCreated); |
|
318 return ret; |
|
319 } |
|
320 storeType=ECompressedRomStore; |
|
321 aArgPtrs[argnum] = NULL; |
|
322 } |
|
323 else if(aArgPtrs[argnum][1]=='n' || aArgPtrs[argnum][1]=='N') |
|
324 { |
|
325 compression=0; |
|
326 aArgPtrs[argnum] = NULL; |
|
327 } |
|
328 else if(aArgPtrs[argnum][1]=='h' || aArgPtrs[argnum][1]=='H') |
|
329 { |
|
330 headerfilename = &aArgPtrs[argnum][2]; |
|
331 aArgPtrs[argnum] = NULL; |
|
332 } |
|
333 else if(aArgPtrs[argnum][1]=='q' || aArgPtrs[argnum][1]=='Q') |
|
334 { |
|
335 quiet=1; |
|
336 aArgPtrs[argnum] = NULL; |
|
337 } |
|
338 else if(aArgPtrs[argnum][1]=='p' || aArgPtrs[argnum][1]=='P') |
|
339 { |
|
340 palettefilename = &aArgPtrs[argnum][2]; |
|
341 aArgPtrs[argnum] = NULL; |
|
342 } |
|
343 } |
|
344 else |
|
345 break; // the RNHQP arguments must precede the output filename |
|
346 } |
|
347 |
|
348 int firstsource=0; |
|
349 while(firstsource<aArgArraySize && aArgPtrs[firstsource]==NULL) |
|
350 firstsource++; |
|
351 if(firstsource==aArgArraySize) firstsource=0; |
|
352 destfilename=aArgPtrs[firstsource]; |
|
353 firstsource++; |
|
354 int numsources=firstsource; |
|
355 while(numsources<aArgArraySize && aArgPtrs[numsources]!=NULL) |
|
356 numsources++; |
|
357 if(numsources==aArgArraySize) numsources=0; |
|
358 numsources-=firstsource; |
|
359 |
|
360 if (numsources > 0) |
|
361 { |
|
362 BitmapCompiler mp(&aArgPtrs[firstsource],numsources); |
|
363 ret = mp.Compile(storeType,compression,destfilename,headerfilename,palettefilename); |
|
364 aDestCreated = true; // The multiple bitmap store has been created/modified |
|
365 } |
|
366 |
|
367 CompilationReport(quiet,ret,storeType,destfilename,&aArgPtrs[firstsource],aNumArgs-firstsource,aDestCreated); |
|
368 |
|
369 return ret; |
|
370 } |
|
371 |
|
372 void GetInfo(char* aSourceFile) |
|
373 { |
|
374 Header(); |
|
375 |
|
376 EpocLoader pl; |
|
377 int numSources=-1; |
|
378 int romFormat=0; |
|
379 int ret = pl.EpocBitmapCount(aSourceFile, numSources, romFormat); |
|
380 if (ret) |
|
381 { |
|
382 cout << "Problem reading number of bitmaps \n"; |
|
383 cout << ErrorMessage(ret) << "\n"; |
|
384 return; |
|
385 } |
|
386 |
|
387 cout << aSourceFile << " is a " << (romFormat? "ROM image":"File store") |
|
388 << " containing " << numSources << ((numSources==1)? " bitmap\n":" bitmaps\n"); |
|
389 |
|
390 for (int count = 0;count<numSources;count++) |
|
391 { |
|
392 ret = pl.LoadEpocBitmap(aSourceFile,count); |
|
393 if (ret == OutOfRange) |
|
394 break; |
|
395 cout << "\n"; |
|
396 if (ret) |
|
397 { |
|
398 cout << "Problem loading bitmap number " << count << "\n"; |
|
399 cout << ErrorMessage(ret) << "\n"; |
|
400 break; |
|
401 } |
|
402 else |
|
403 { |
|
404 SEpocBitmapHeader h = pl.Header(); |
|
405 cout << "Bitmap " << count + 1 << " information:\n"; |
|
406 cout << "Pixel size " << h.iWidthInPixels << " x " << h.iHeightInPixels << "\n"; |
|
407 cout << "Twips size " << h.iWidthInTwips << " x " << h.iHeightInTwips << "\n"; |
|
408 cout << h.iBitsPerPixel << " Bpp "; |
|
409 if (h.iColor == EColorBitmap) |
|
410 cout << "Colour"; |
|
411 else if (h.iColor == EColorBitmapAlpha || h.iColor == EColorBitmapAlphaPM) |
|
412 cout << "Colour with alpha channel"; |
|
413 else if(h.iColor == EMonochromeBitmap) |
|
414 cout << "Monochrome"; |
|
415 else |
|
416 cout << "Unknown colour format"; |
|
417 cout << "\n"; |
|
418 if (h.iPaletteEntries > 0) |
|
419 cout << "Palette entries " << h.iPaletteEntries; |
|
420 |
|
421 int byteSize = BitmapUtils::ByteWidth(h.iWidthInPixels,h.iBitsPerPixel) * h.iHeightInPixels; |
|
422 int compressionRatio = 0; |
|
423 if (byteSize > 0) |
|
424 compressionRatio = (h.iBitmapSize - sizeof(SEpocBitmapHeader)) * 100 / byteSize; |
|
425 |
|
426 switch (h.iCompression) |
|
427 { |
|
428 case ENoBitmapCompression: |
|
429 cout << "No compression\n"; |
|
430 break; |
|
431 case EByteRLECompression: |
|
432 cout << "Bytewise RLE compression " << compressionRatio << "%\n"; |
|
433 break; |
|
434 case ETwelveBitRLECompression: |
|
435 cout << "12 bit RLE compression " << compressionRatio << "%\n"; |
|
436 break; |
|
437 case ESixteenBitRLECompression: |
|
438 cout << "16 bit RLE compression " << compressionRatio << "%\n"; |
|
439 break; |
|
440 case ETwentyFourBitRLECompression: |
|
441 cout << "24 bit RLE compression " << compressionRatio << "%\n"; |
|
442 break; |
|
443 case EThirtyTwoUBitRLECompression: |
|
444 cout << "unsigned 32 bit RLE compression (no alpha channel) " << compressionRatio << "%\n"; |
|
445 break; |
|
446 case EThirtyTwoABitRLECompression: |
|
447 cout << "unsigned 32 bit RLE compression (with alpha channel) " << compressionRatio << "%\n"; |
|
448 break; |
|
449 // case ERLECompressionLast: // Added to supress unhandled switch warning |
|
450 default: |
|
451 break; |
|
452 } |
|
453 } |
|
454 } |
|
455 |
|
456 cout << "\n"; |
|
457 } |
|
458 |
|
459 class TAutoPtr |
|
460 { |
|
461 public: |
|
462 TAutoPtr(char** aPtr) : |
|
463 iPtr(aPtr) |
|
464 { |
|
465 } |
|
466 ~TAutoPtr() |
|
467 { |
|
468 delete iPtr; |
|
469 } |
|
470 private: |
|
471 char** iPtr; |
|
472 }; |
|
473 |
|
474 int main(int argc,char* argv[],char* []) |
|
475 { |
|
476 if (argc <= 1) |
|
477 { |
|
478 Usage(); |
|
479 return 0; |
|
480 } |
|
481 |
|
482 int optMaxCnt = argc; |
|
483 |
|
484 if(argc==2) // The single argument must be a command file name |
|
485 { |
|
486 struct stat fileinfo; |
|
487 if (stat(argv[1],&fileinfo)==-1) |
|
488 { |
|
489 Report(CommandFile); |
|
490 return 0; |
|
491 } |
|
492 optMaxCnt = fileinfo.st_size; |
|
493 } |
|
494 |
|
495 char** argptrs = new char*[optMaxCnt]; |
|
496 if(!argptrs) |
|
497 { |
|
498 Report(NoMemory); |
|
499 return 0; |
|
500 } |
|
501 TAutoPtr autoPtr(argptrs); |
|
502 memset(argptrs, 0, optMaxCnt * sizeof(char*)); |
|
503 |
|
504 int numargs = 0; |
|
505 if(argc>2) // Explicit arguments are present |
|
506 { |
|
507 for(int count=0;count<argc-1;count++) |
|
508 argptrs[count]=argv[count+1]; |
|
509 numargs = argc-1; |
|
510 } |
|
511 else // The single argument must be a command file name |
|
512 { |
|
513 int ret = ProcessCommandFile(argv[1],argptrs,numargs); |
|
514 if (ret) |
|
515 { |
|
516 Report(ret); |
|
517 return 0; |
|
518 } |
|
519 } |
|
520 |
|
521 if ((argptrs[0]!=NULL && (argptrs[0][0]==OPTCHAR || argptrs[0][0]==ALTERNATE_OPTCHAR)) && (argptrs[0][1]=='u' || argptrs[0][1]=='U')) { |
|
522 return Decompile(argc,numargs,argptrs); } |
|
523 |
|
524 if ((argptrs[0]!=NULL && (argptrs[0][0]==OPTCHAR || argptrs[0][0]==ALTERNATE_OPTCHAR)) && (argptrs[0][1]=='v' || argptrs[0][1]=='V')) |
|
525 { |
|
526 GetInfo(argptrs[1]); |
|
527 return 0; |
|
528 } |
|
529 |
|
530 return Compile(numargs,optMaxCnt,argptrs); |
|
531 } |
|
532 |