graphicstools/gdi_tools/bmconv/MAINFUNC.CPP
author Faisal Memon <faisal.memon@nokia.com>
Thu, 09 Sep 2010 18:17:30 +0100
branchNewGraphicsArchitecture
changeset 175 c03ff11acab3
parent 0 5d03bc08d59c
permissions -rw-r--r--
Export new s4 egl extensions bitmap for the SF wiki

// Copyright (c) 1997-2009 Nokia Corporation and/or its subsidiary(-ies).
// All rights reserved.
// This component and the accompanying materials are made available
// under the terms of "Eclipse Public License v1.0"
// which accompanies this distribution, and is available
// at the URL "http://www.eclipse.org/legal/epl-v10.html".
//
// Initial Contributors:
// Nokia Corporation - initial contribution.
//
// Contributors:
//
// Description:
//

#if defined(__MSVCDOTNET__) || defined(__TOOLS2__)
#include <ostream>
#include <iostream>
using namespace std;
#else //!__MSVCDOTNET__ && !__TOOLS2__
#include <ostream.h>
#endif //__MSVCDOTNET__

#include "TOOLSVER.H"
#include "BMCONV.H"
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>


/**
Returns an informative error message, the result of the program actions performed.
@return Informative error string
@param aErrorNumber The error returned from the actions performed
@param aDestfile The multiple bitmap store file name
@param aDestCreated True if the multiple bitmap store has been created/modified
*/

char* ErrorMessage(int aErrorNumber, char* aDestfile=NULL, bool aDestCreated=false)
	{
	// Remove the multiple bitmap store if it has been created/modified during an fstream session and there has been an error
	if(aDestfile && (aErrorNumber != NoError) && (aDestCreated == true))
		{
		remove(aDestfile);
		}

	switch(aErrorNumber)
		{
		case NoError:
			return "Success.";
		case NoMemory:
			return "Out of memory.";
		case Arg:
			return "Bad argument.";
		case Files:
			return "File does not exist";
		case SourceFile:
			return "Bad source file(s).";
		case DestFile:
			return "Bad destination file(s).";
		case CommandFile:
			return "Bad command file.";
		case OutOfRange:
			return "Number of sources/targets mismatch.";
		case TooManyArgs:
			return "Too many arguments.";
		case UnknownCompression:
			return "Unknown source compression type.";
		case CompressionError:
			return "Compression error.";
		case DecompressionError:
			return "Decompression error.";
		case Bpp:
			return "Invalid bitmap mode specified.";
		case PaletteFile:
			return "Bad palette file.";
		case PaletteSupportNotImplemented:
			return "Palettes not supported";
		case AlphaFiles:
			return "Alpha bitmap file does not exist";
		case AlphaDimensions:
			return "Alpha channel bitmap's dimensions don't match pixel bitmap's dimensions.";
		case AlphaBpp:
			return "Alpha channel bitmap must be 8bpp.";
		default:
			return "Unknown error!";
		};
	}

void Header()
	{
	cout << "\n";
	cout << "\n";
	cout << "BMCONV version "<< version << ".\n";
	}
	
void Report(int aError)
	{
	Header();
	cout << ErrorMessage(aError) << "\n";
	}

/**
Compiliation information to print to the user at the end of the program.
@param aQuiet Flag if the user selected quiet output mode
@param aError The error returned from the actions performed
@param aType The multiple bitmap store type created
@param aDestfile The multiple bitmap store file name
@param aBitmapFiles The array of bitmaps used
@param aNumFiles The amount of bitmaps used
@param aDestCreated True if the multiple bitmap store has been created/modified
*/

void CompilationReport(int aQuiet,int aError,TStoreType aType,char* aDestfile,char** aBitmapFiles,int aNumFiles, bool aDestCreated)
	{	
	if(!aQuiet || aError)
		{
		Header();
		cout << "Compiling...\n";
		if(aType!=ENoStore)
			cout << "Multiple bitmap store type: ";
		if(aType==EFileStore)
			cout << "File store" << "\n";
		else if(aType==ERomStore)
			cout << "ROM image store" << "\n";
		else if(aType==ECompressedRomStore)
			cout << "Compressed ROM image store" << "\n";
		if(aDestfile!=NULL)
			cout << "Epoc file: " << aDestfile << "\n\n";
		for(int count=0;count<aNumFiles;count++)
			{
			cout << "Bitmap file " << count+1 << "	: ";
			cout << aBitmapFiles[count] << "\n";
			}
		cout << ErrorMessage(aError, aDestfile, aDestCreated) << "\n";
		}
	}
	
void DecompilationReport(int aError,char* aDestfile,char** aBitmapFiles,int aNumFiles)
	{	
	Header();
	cout << "Decompiling...\n";
	if(aDestfile!=NULL)
		cout << "Epoc file: " << aDestfile << "\n\n";
	for(int count=0;count<aNumFiles;count++)
		{
		cout << "Bitmap file " << count+1 << "	: ";
		cout << aBitmapFiles[count] << "\n";
		}
	cout << ErrorMessage(aError) << "\n";
	}
	
void Usage()
    {
	cout << "\n";
	cout << "BMCONV version "<< version << ".\n";
	cout << "Symbian OS multiple bitmap file/rom store conversion program.\n";
	cout << "Copyright (c) 2007 Nokia Corporation and/or its subsidiary(-ies).";
	cout << "\n";
	cout << "\n";
	cout << "Usage:\n";
	cout << "BMCONV [-r|-s|-n] [-hfilename] [-q] [-pfilename] epocfile [OPT]bmp_1 ... [OPT]bmp_n\n";
	cout << "BMCONV [-r|-s|-n] [-q] [-pfilename] epocfile -mepocfile2\n";
	cout << "BMCONV -u epocfile bmp_1 [... bmp_n]\n";
	cout << "BMCONV -v epocfile\n";
	cout << "BMCONV commandfile\n";
	cout << "\n";
	cout << " -r specifies a ROM image destination file,\n";
	cout << " -s specifies a compressed ROM image file,\n";
	cout << " -n disables bitmap File Store compression,\n";
	cout << " the default is a compressed File Store file.\n\n";
	cout << " -q specifies quiet mode - only errors are reported.\n\n";
	cout << " -hfilename specifies the filename for the automatic\n";
	cout << " generation of a header file for inclusion into code.\n\n";
	cout << " -pfilename gives the filename of a palette file containing 256 hex\n";
	cout << " numbers (0x00BBGGRR) specifying the palette for 8bpp colour bitmaps.\n";
	cout << " (Omission results in the use of a default palette.)\n\n";
	cout << " OPT may be one of -1, -2, -4, -8, -c4, -c8, -c12, -c16, -c24 -c32 -c32a\n";
	cout << " specifying bits per pixel and grey-scale-colour, or -mepocfile2\n";
	cout << " to specify an existing multiple bitmap file. default is -2.\n\n";
	cout << " To avoid ambiguity when specifying -c32 with a bitmap file whose name\n";
	cout << " begins with an 'a', use a relative or direct directory reference\n";
	cout << " e.g. -c32.\\abitmap.bmp or -c32c:\\abitmap.bmp\n";
	cout << " Directory names must not include spaces.\n\n";
	cout << " -c32a specifies use of an alpha channel in a 32bpp bitmap. Alpha data\n";
	cout << " is supplied in a separate 8bpp bmp file with identical dimensions to\n";
	cout << " the pixel data. This file must be named as bmp_n with the suffix '-alpha'\n";
	cout << " e.g. if bmp_1 is 'my.bmp' then the file 'my-alpha.bmp' is required in the\n";
	cout << " same directory.  The alpha file does not need to be specified.\n\n";
	cout << " epocfile specifies the epoc multi-bitmap file name.\n";
	cout << " bmp_n specifies the nth bitmap file name.\n\n";
	cout << " -u decompiles epocfile to bmp_1,...,bmp_n.\n";
	cout << " If an alpha channel is present then a further, 8bpp file is output for \n";
	cout << " the alpha data, named with an '-alpha' suffix as described above.\n\n";
	cout << " -v displays a summary of the bitmaps in epocfile\n";
	cout << " otherwise bmp_1,...,bmp_n are compiled to epocfile\n\n";
	cout << " commandfile specifies a file containing the commandline\n";
	cout << " with commands separated by spaces or newlines.\n\n";
	cout << " When bmconv is used on Windows, options may start with '/' or '-'\n";

	}

int IsWhiteSpace(char aCharacter)
	{
	return(aCharacter==' ' || aCharacter=='\n' || aCharacter=='\r' || aCharacter==0x1a);
	}

int ProcessCommandFile(char* aCommandFileName,char** aArgPtrs,int& aNumArgs)
    {
	struct stat fileinfo;
	if (stat(aCommandFileName,&fileinfo)==-1)
		return CommandFile;

	int filesize=fileinfo.st_size;
	if (filesize==0)
		return NoError;
#if defined(__MSVCDOTNET__) || defined(__TOOLS2__)
	fstream commandfile(aCommandFileName, ios::in | ios::binary);
#else //!__MSVCDOTNET__
	fstream commandfile(aCommandFileName, ios::in | ios::binary | ios::nocreate);
#endif //__MSVCDOTNET__
	if(!commandfile.is_open())
		return CommandFile;

	char* commandData=new char[filesize+1];
	if(commandData==NULL)
		return NoMemory;

	memset(commandData,0,filesize+1);
	commandfile.read(commandData,filesize);
	commandData[filesize]='\0';

	char* commandptr = (char*)commandData;
	char* commandptrLimit = (char*)(commandData + filesize);
	while (commandptr < commandptrLimit)
		{
		if(*commandptr=='/' && *(commandptr+1)=='/')
			while(*commandptr!='\n' && *commandptr!='\r' && commandptr < commandptrLimit)
				*commandptr++=' ';
		else if (*commandptr==0x1a)
			*commandptr++=' ';
		commandptr++;
		}

	commandptr = (char*)commandData;
	while (commandptr < commandptrLimit)
		{
		while(IsWhiteSpace(*commandptr) && commandptr < commandptrLimit)
			*commandptr++='\0';
		if (commandptr == commandptrLimit)
			break;
		aArgPtrs[aNumArgs]=commandptr;
		while(!IsWhiteSpace(*commandptr) && commandptr < commandptrLimit)
			commandptr++;
		if (commandptr == commandptrLimit)
			break;
		aNumArgs++;
		}

	commandfile.close();
	return NoError;
    }

int Decompile(int aArgc,int aNumArgs,char** aArgPtrs)
	{
	int ret=OutOfRange;
	char* destfilename=aArgPtrs[1];

	if(aArgc>=4 || aArgc==2)
		{
		for(int count=2;count<aNumArgs;count++)
			{
			EpocLoader pl;
      ret=pl.LoadEpocBitmap(destfilename,count-2);
      if(!ret) ret=pl.SaveBitmap(aArgPtrs[count]);
      if(ret) break;
			}
		DecompilationReport(ret,destfilename,&aArgPtrs[2],aNumArgs-2);
		}
	else
		DecompilationReport(ret,NULL,NULL,0);

	return ret;
	}

int Compile(int aNumArgs,int aArgArraySize, char** aArgPtrs)
	{
	TStoreType storeType = EFileStore;
	int compression = 1;
	int quiet = 0;
	char* headerfilename = NULL;
	char* palettefilename = NULL;
	char* destfilename = NULL;
	int ret = OutOfRange;
	bool aDestCreated = false;

	for(int argnum=0;argnum<aNumArgs;argnum++)
		{
		if(aArgPtrs[argnum] && (aArgPtrs[argnum][0] == OPTCHAR || aArgPtrs[argnum][0]==ALTERNATE_OPTCHAR))
			{
			if(aArgPtrs[argnum][1]=='r' || aArgPtrs[argnum][1]=='R')
				{
				if(storeType==ECompressedRomStore)
					{
					ret=TooManyArgs;
					CompilationReport(quiet,ret,storeType,NULL,NULL,0,aDestCreated);
					return ret;
					}
				storeType=ERomStore;
				aArgPtrs[argnum] = NULL;
				}
			else if(aArgPtrs[argnum][1]=='s' || aArgPtrs[argnum][1]=='S')
				{
				if(storeType==ERomStore)
					{
					ret=TooManyArgs;
					CompilationReport(quiet,ret,storeType,NULL,NULL,0,aDestCreated);
					return ret;
					}
				storeType=ECompressedRomStore;
				aArgPtrs[argnum] = NULL;
				}
			else if(aArgPtrs[argnum][1]=='n' || aArgPtrs[argnum][1]=='N')
				{
				compression=0;
				aArgPtrs[argnum] = NULL;
				}
			else if(aArgPtrs[argnum][1]=='h' || aArgPtrs[argnum][1]=='H')
				{
				headerfilename = &aArgPtrs[argnum][2];
				aArgPtrs[argnum] = NULL;
				}
			else if(aArgPtrs[argnum][1]=='q' || aArgPtrs[argnum][1]=='Q')
				{
				quiet=1;
				aArgPtrs[argnum] = NULL;
				}
			else if(aArgPtrs[argnum][1]=='p' || aArgPtrs[argnum][1]=='P')
				{
				palettefilename = &aArgPtrs[argnum][2];
				aArgPtrs[argnum] = NULL;
				}
			}
		else
			break;		// the RNHQP arguments must precede the output filename
		}

	int firstsource=0;
	while(firstsource<aArgArraySize && aArgPtrs[firstsource]==NULL)
		firstsource++;
	if(firstsource==aArgArraySize) firstsource=0;
	destfilename=aArgPtrs[firstsource];
	firstsource++;
	int numsources=firstsource;
	while(numsources<aArgArraySize && aArgPtrs[numsources]!=NULL)
		numsources++;
	if(numsources==aArgArraySize) numsources=0;
	numsources-=firstsource;

	if (numsources > 0)
		{
		BitmapCompiler mp(&aArgPtrs[firstsource],numsources);
		ret = mp.Compile(storeType,compression,destfilename,headerfilename,palettefilename);
		aDestCreated = true;		// The multiple bitmap store has been created/modified
		}

	CompilationReport(quiet,ret,storeType,destfilename,&aArgPtrs[firstsource],aNumArgs-firstsource,aDestCreated);

	return ret;
	}

void GetInfo(char* aSourceFile)
	{
	Header();

	EpocLoader pl;
	int numSources=-1;
	int romFormat=0;
	int ret = pl.EpocBitmapCount(aSourceFile, numSources, romFormat);
	if (ret)
		{
		cout << "Problem reading number of bitmaps \n";
		cout << ErrorMessage(ret) << "\n";
		return;
		}

	cout << aSourceFile << " is a " << (romFormat? "ROM image":"File store") 
		<< " containing " << numSources << ((numSources==1)? " bitmap\n":" bitmaps\n");

	for (int count = 0;count<numSources;count++)
		{
		ret = pl.LoadEpocBitmap(aSourceFile,count);
		if (ret == OutOfRange)
			break;
		cout << "\n";
		if (ret)
			{
			cout << "Problem loading bitmap number " << count << "\n";
			cout << ErrorMessage(ret) << "\n";
			break;
			}
		else
			{
			SEpocBitmapHeader h = pl.Header();
			cout << "Bitmap " << count + 1 << " information:\n";
			cout << "Pixel size " << h.iWidthInPixels << " x " << h.iHeightInPixels << "\n";
			cout << "Twips size " << h.iWidthInTwips << " x " << h.iHeightInTwips << "\n";
			cout << h.iBitsPerPixel << " Bpp ";
			if (h.iColor == EColorBitmap)
				cout << "Colour";
			else if (h.iColor == EColorBitmapAlpha || h.iColor == EColorBitmapAlphaPM)
				cout << "Colour with alpha channel";
			else if(h.iColor == EMonochromeBitmap)
				cout << "Monochrome";
			else
				cout << "Unknown colour format";
			cout << "\n";
			if (h.iPaletteEntries > 0)
				cout << "Palette entries " << h.iPaletteEntries;

			int byteSize = BitmapUtils::ByteWidth(h.iWidthInPixels,h.iBitsPerPixel) * h.iHeightInPixels;
			int compressionRatio = 0;
			if (byteSize > 0)
				compressionRatio = (h.iBitmapSize - sizeof(SEpocBitmapHeader)) * 100 / byteSize;

			switch (h.iCompression)
				{
			case ENoBitmapCompression:
				cout << "No compression\n";
				break;
			case EByteRLECompression:
				cout << "Bytewise RLE compression " << compressionRatio << "%\n";
				break;
			case ETwelveBitRLECompression:
				cout << "12 bit RLE compression " << compressionRatio << "%\n";
				break;
			case ESixteenBitRLECompression:
				cout << "16 bit RLE compression " << compressionRatio << "%\n";
				break;
			case ETwentyFourBitRLECompression:
				cout << "24 bit RLE compression " << compressionRatio << "%\n";
				break;
			case EThirtyTwoUBitRLECompression:
				cout << "unsigned 32 bit RLE compression (no alpha channel) " << compressionRatio << "%\n";
				break;
			case EThirtyTwoABitRLECompression:
				cout << "unsigned 32 bit RLE compression (with alpha channel) " << compressionRatio << "%\n";
				break;
		//	case ERLECompressionLast: // Added to supress unhandled switch warning
			default:
				break;
				}
			}
		}

	cout << "\n";
	}

class TAutoPtr
	{
public:
	TAutoPtr(char** aPtr) :
		iPtr(aPtr)
		{
		}
	~TAutoPtr()
		{
		delete iPtr;
		}
private:
	char** iPtr;
	};

int main(int argc,char* argv[],char* [])
    {
	if (argc <= 1)
		{
		Usage();
		return 0;
		}

	int optMaxCnt = argc;

	if(argc==2) // The single argument must be a command file name
		{
		struct stat fileinfo;
		if (stat(argv[1],&fileinfo)==-1)
			{
			Report(CommandFile);
			return 0;
			}
		optMaxCnt = fileinfo.st_size;
		}

	char** argptrs = new char*[optMaxCnt];
	if(!argptrs)
		{
		Report(NoMemory);
		return 0;
		}
	TAutoPtr autoPtr(argptrs);
	memset(argptrs, 0, optMaxCnt * sizeof(char*));

	int numargs = 0;
	if(argc>2) // Explicit arguments are present
		{
		for(int count=0;count<argc-1;count++)
			argptrs[count]=argv[count+1];
		numargs = argc-1;
		}
	else // The single argument must be a command file name
		{
		int ret = ProcessCommandFile(argv[1],argptrs,numargs);
		if (ret)
			{
			Report(ret);
			return 0;
			}
		}

	if ((argptrs[0]!=NULL && (argptrs[0][0]==OPTCHAR || argptrs[0][0]==ALTERNATE_OPTCHAR)) && (argptrs[0][1]=='u' || argptrs[0][1]=='U')) {
		return Decompile(argc,numargs,argptrs); }

	if ((argptrs[0]!=NULL && (argptrs[0][0]==OPTCHAR || argptrs[0][0]==ALTERNATE_OPTCHAR)) && (argptrs[0][1]=='v' || argptrs[0][1]=='V'))
		{
		GetInfo(argptrs[1]);
		return 0;
		}

	return Compile(numargs,optMaxCnt,argptrs);
    }