gfxconversion/bmconv_s60/src/MAINFUNC.CPP
author Simon Howkins <simonh@symbian.org>
Wed, 10 Nov 2010 00:18:53 +0000
branchRCL_3
changeset 46 476f0ee3c373
parent 0 f453ebb75370
permissions -rw-r--r--
Added useful diagnostics that explain why raptor is redefining commands for a target (when processing things through the mifconv.flm). This should make it much easier to pinpoint how the system model should be adjusted to avoid the warnings in future. Also simplified the existing redefinition guards.

/*
* Copyright (c) 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__) || defined(__CW32__)
#include <ostream>
#include <iostream>
using namespace std;
#else //!__MSVCDOTNET__ && !__TOOLS2__ && !__CW32__
#pragma warning(disable: 4100)
#pragma warning(disable: 4511)
#pragma warning(disable: 4512)
#pragma warning(disable: 4530)
#pragma warning(disable: 4663)
#pragma warning(disable: 4710)
#pragma warning(disable: 4786)
#pragma warning(disable: 4800)
#include <ostream.h>
#endif //__MSVCDOTNET__

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

const int KMaxPaletteFileLen = 256;

#ifdef __linux__
const char* DefaultPaletteFileSearchLocations[] =
{
    "/epoc32/include/mw/ThirdPartyBitmap.pal",
    "/epoc32/include/middleware/ThirdPartyBitmap.pal",
    "/epoc32/include/ThirdPartyBitmap.pal"
};
#else
const char* DefaultPaletteFileSearchLocations[] =
{
    "\\epoc32\\include\\mw\\ThirdPartyBitmap.pal",
    "\\epoc32\\include\\middleware\\ThirdPartyBitmap.pal",
    "\\epoc32\\include\\ThirdPartyBitmap.pal"
};
#endif

/**
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 S60 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,TSourceFile* 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 << "	: ";
			aBitmapFiles[count].WriteCompileInfo(cout);
			cout << endl;
			}
		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 S60 version "<< version << ".\n";
	cout << "Symbian OS multiple bitmap file/rom store conversion program.\n";
	cout << "Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). All rights reserved.";
	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__) || defined(__CW32__)
	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;
        if ( (*commandptr == '/') && (*(commandptr+1) == 'p'||*(commandptr+1) == 'P') && (*(commandptr+2) == '"') )
            {
            commandptr+=3;
            while(*commandptr != '"')
                commandptr++;
            *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;
	}

const char* AddEpocRootTo(std::string& aBuf, const std::string& aName)
	{ 
	int nameLen = aName.length();
	int rootLen = 0;
	aBuf = ""; // Clear old contents
	char* epocroot = getenv("EPOCROOT");
	if (epocroot)
		{
		rootLen = strlen(epocroot);
		if (nameLen+rootLen < KMaxPaletteFileLen)
			{
			if( rootLen > 0 && epocroot[rootLen-1] == '\\')
			    {
			    aBuf = std::string(epocroot, rootLen-1);
			    }
			else if( rootLen > 0 )
			    {
			    aBuf = std::string(epocroot);
			    }
			}
		}
	aBuf += aName;
	return aBuf.c_str();
	}

bool FileExists( const char* aFileName )
{
  struct stat fileInfo;   
  int retVal = 0; 

  // Try to get file attributes to see if the file exists or not:
  retVal = stat( aFileName, &fileInfo); 
  return retVal == 0;
}

const char* DefaultPaletteFileName(std::string& aBuf)
    {
    const char* palettefilename = NULL;    
    int numOfSearchLocations = sizeof(DefaultPaletteFileSearchLocations)/sizeof(char*);
    
    for( int i = 0; i < numOfSearchLocations; ++i )
        {
        palettefilename = AddEpocRootTo(aBuf, DefaultPaletteFileSearchLocations[i]);
        if( FileExists( palettefilename))
            {
            return palettefilename;
            }
        }
    
    return NULL;
    }

int Compile(int aNumArgs,int aArgArraySize, char** aArgPtrs)
	{
	TStoreType storeType = EFileStore;
	int compression = 1;
	int quiet = 0;
	char* headerfilename = NULL;
	char paletteBuf[KMaxPaletteFileLen];
	memset(paletteBuf, 0, KMaxPaletteFileLen);
	std::string paletteStr;	
	const char* defaultPalettefile = DefaultPaletteFileName(paletteStr);
	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')
				{
				if (getenv("BMCONV_NOT_QUIET") == 0)
					quiet=1;
				aArgPtrs[argnum] = NULL;
				}
			else if(aArgPtrs[argnum][1]=='p' || aArgPtrs[argnum][1]=='P')
				{
				palettefilename = &aArgPtrs[argnum][2];
                if (*palettefilename=='"')
                    {
                    palettefilename+=1;
                    }
				aArgPtrs[argnum] = NULL;
				}
			}
		else
			break;		// the RNHQP arguments must precede the output filename
		}

	if( palettefilename == NULL )
	    {
	    // Palette file not given in arguments. If the default palette file
	    // was found, use it, otherwise return error.
	    if( defaultPalettefile != NULL )
	        {
	        memcpy(paletteBuf, defaultPalettefile, strlen(defaultPalettefile));
	        palettefilename = paletteBuf;
	        }
	    else
	        {
	        // Palettefile not given in arguments nor found from default locations:
	        ret = PaletteFile;
	        CompilationReport(quiet,ret,storeType,NULL,NULL,0,aDestCreated);
	        return ret;
	        }
	    }
	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;

	TSourceFile* sources = 0;

	if (numsources > 0)
		{
		sources = new TSourceFile[numsources];
		for (int ii=0; ii<numsources; ii++)
			sources[ii].FileName() = aArgPtrs[firstsource + ii];
		BitmapCompiler mp(sources,numsources);
		ret = mp.Compile(storeType,compression,destfilename,headerfilename,palettefilename);
		aDestCreated = true;		// The multiple bitmap store has been created/modified
		}

	CompilationReport(quiet,ret,storeType,destfilename,sources,aNumArgs-firstsource,aDestCreated);
	delete [] sources;

	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)
				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);
    }