bintools/rcomp/src/main.cpp
changeset 0 044383f39525
child 590 360bd6b35136
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bintools/rcomp/src/main.cpp	Tue Oct 27 16:36:35 2009 +0000
@@ -0,0 +1,568 @@
+/*
+* Copyright (c) 2000-2009 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of the License "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: 
+*
+*/
+
+
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "unistd.h"
+
+#if defined( __MSVCDOTNET__) || defined(__TOOLS2__)
+#include <iostream>
+using std::cout;
+using std::endl;
+using std::cerr;
+#else //!__MSVCDOTNET__
+#ifndef __LINUX__
+#include <io.h>
+#endif //!__LINUX__
+#endif //__MSVCDOTNET__
+
+#include "RESOURCE.H"
+#include "DATATYPE.H"
+#include "MEM.H"     
+#include "RCBINSTR.H"
+#include "NUMVAL.H"  
+#include "ERRORHAN.H"
+#include "FILEACC.H" 
+#include "VERSION.H" 
+#include "CTABLE.H"  
+#include "main.h"
+#include "TOKENS.H"
+#include "localise.h"
+#include "qualifar.h"
+#include "messages.h"
+
+extern NameIdMap* pResourceNameIds;
+extern long CurrentId;
+
+void WriteHeaderFile(FILE* aRSG, IndexTable& aIndex)
+	{
+	IndexTableIterator next(aIndex);
+	IndexTableItem * p;
+	while( ( p = next() ) != NULL)
+		{
+		ResourceHeader& r=p->Resource();
+		if (r.iLabel.Length()>0 && !r.iLocal)
+			{
+			r.iLabel.Upper();
+			if (r.iFormatAsHex)
+				fprintf(aRSG, "#define %-41s 0x%x\n", r.iLabel.GetAssertedNonEmptyBuffer(), r.iResourceId);
+			else
+				fprintf(aRSG, "#define %-41s %d\n", r.iLabel.GetAssertedNonEmptyBuffer(), r.iResourceId);
+			}
+		}
+	}
+
+void WriteBitArrayOfResourcesContainingCompressedUnicode(RCBinaryStream& aRSC, const IndexTable& aIndex)
+	{
+	IndexTableIterator next(aIndex);
+	unsigned char bitBuffer = 0;
+	int numberOfBitsInBuffer = 0;
+	for (;;)
+		{
+		IndexTableItem* const p = next();
+		if (p == NULL)
+			{
+			if (numberOfBitsInBuffer > 0)
+				{
+				aRSC.Write(&bitBuffer, 1);
+				}
+			break;
+			}
+		if (p->Resource().ContainsCompressedUnicode())
+			{
+			bitBuffer |= (1 << numberOfBitsInBuffer);
+			}
+		++numberOfBitsInBuffer;
+		if (numberOfBitsInBuffer == 8)
+			{
+			aRSC.Write(&bitBuffer, 1);
+			bitBuffer = 0;
+			numberOfBitsInBuffer = 0;
+			}
+		}
+	}
+
+void WriteBinaryResourceData(RCBinaryStream& aRSC, IndexTable& aIndex, int& aSizeOfLargestResourceWhenUncompressed, const char* aDumpDirectory)
+	{
+	IndexTableIterator next(aIndex);
+	IndexTableItem * p;
+	int resourceIndex=1;
+	while( ( p = next() ) != NULL)
+		{
+		char* dumpFile=NULL;
+		if (aDumpDirectory!=NULL)
+			{
+			dumpFile=new char[strlen(aDumpDirectory)+20];
+			strcpy(dumpFile, aDumpDirectory);
+			char resourceIndexAsString[20];
+			sprintf(resourceIndexAsString, "%d", resourceIndex);
+			strcat(dumpFile, resourceIndexAsString);
+			}
+		p->SetOffset(aRSC.GetPosition()); // record start of this resource in the index
+		p->Resource().StreamOut(aRSC, aSizeOfLargestResourceWhenUncompressed, dumpFile); // write out binary form of resource
+		delete [] dumpFile;
+		++resourceIndex;
+		}
+	}
+
+void WriteResourceFile(RCBinaryStream& aRSC, IndexTable& aIndex, bool aThirdUidIsOffset, const char* aDumpDirectory)
+	{
+	char flags=0;
+	if (aThirdUidIsOffset)
+		{
+		flags|=0x01;
+		}
+	aRSC << flags; // these flags are to be used only by a dictionary-compressing program rather than to be used directly by Bafl when reading non-dictionary-compressed resource files (as output by Rcomp)
+	const int positionToOverWriteFrom=aRSC.GetPosition();
+	NumericValue twoByteSizeOfLargestResourceWhenUncompressed(L_WORD);
+	aRSC << twoByteSizeOfLargestResourceWhenUncompressed;
+	WriteBitArrayOfResourcesContainingCompressedUnicode(aRSC, aIndex); // simply makes space for the bit-array without writing anything sensible in it (as we don't yet know which resources will contain compressed Unicode)
+	int sizeOfLargestResourceWhenUncompressed=0;
+	WriteBinaryResourceData(aRSC, aIndex, sizeOfLargestResourceWhenUncompressed, aDumpDirectory);
+	aIndex.SetIndexOffset(aRSC.GetPosition());
+	aRSC << aIndex;
+	aRSC.SetPosition(positionToOverWriteFrom);
+	twoByteSizeOfLargestResourceWhenUncompressed=sizeOfLargestResourceWhenUncompressed;
+	aRSC << twoByteSizeOfLargestResourceWhenUncompressed;
+	WriteBitArrayOfResourcesContainingCompressedUnicode(aRSC, aIndex); // overwrites the bit array with correct data
+
+	if(verbose) 
+		{
+		MOFF; cout << aIndex; cout << endl; MON;
+		}
+	}
+
+void CheckLabels() // checks whether the labels that are used in the input have been declared
+	{
+	QualifiedStringArrayIterator nextLabel(pG->UsedIdentifiers);
+	QualifiedString * pLabel;
+	while ((pLabel = nextLabel() ) != NULL)
+		{
+		bool found = false; // gets set to true if the label in question is declared
+		StringArrayIterator nextDeclared(pG->AllIdentifiers);
+		String * pDeclared;
+		while ( ( (pDeclared = nextDeclared() ) != NULL) && ( ! found ))
+			{
+			StringLess stringCompare;
+			if( !stringCompare(*pDeclared,(*pLabel).GetEntry()) && !stringCompare((*pLabel).GetEntry(),*pDeclared) )
+				{ // this comparison returns true if the label is the same as the declared label
+				found = true;
+				}
+			}
+		if( ! found ) // if label hasn't been declared emit warning
+			{
+			Message * message = pG->Messages.GetEntry(LT_045);
+			String fileName = (*pLabel).GetFileName();
+			int lineNumber = (*pLabel).GetLineNumber();
+			if(message->GetActivated())
+				{
+				String comment = message->GetMessageOutput();
+				comment += (*pLabel).GetEntry();
+				ErrorHandler::OutputWholeLine(fileName, lineNumber, comment);
+				}
+			}
+		}
+	}
+
+
+/*  Tokenize expects a string in the following format:
+ *	  \d{3}(,\d{3})*
+ *  i.e. comma-separated three digit numbers. 
+ *  The string should contain no whitespace.
+ */
+void Tokenize(String aString)
+	{
+	int length = aString.Length();
+
+	for(int end=3; end<=length; end+=4)
+		{
+		String messageNumber = aString.ExtractSubString(end-3,end-1);
+		if(messageNumber.IsDecNatural())
+			{
+			Message * message = pG->Messages.GetTextEntry(messageNumber);
+			if(message != NULL)
+				{
+				message->SetActivationStatus(false);
+				}
+			}
+		}
+	}
+				
+
+void OutputHelp()
+	{
+	cerr << "Resource compiler version " << version << " (Build " << build << ") (C) 1997-2009 Nokia Corporation." << endl;
+	cerr << "Usage: rcomp [-vpul] [-force] [-oRSCFile] [-{uid2,uid3}] [-hHeaderFile] [-sSourceFile] [-iBaseInputFileName]" << endl;
+	cerr << "\tv" << "\tverbose" << endl;
+	cerr << "\tp" << "\tParser debugging" << endl;
+	cerr << "\tl" << "\tCheck localisation comments" << endl;
+	cerr << "\tforce" << "\tEmit localisation warnings even if no localisation tags are present" << endl;
+	cerr << "\tadd-defaults" << "\tAmend input rss/rpp file to add missing default localisation options" << endl;
+	cerr << endl;
+	cerr << "\tu" << "\tGenerate Unicode resource binary" << endl;
+	cerr << endl;
+	cerr << "If no source file is specified, the source will be read from standard input." << endl;
+	cerr << "(-i is used to specify the file given to the preprocessor this " << endl;
+	cerr << "    name is used in generating debug output.)" << endl;
+	}
+
+
+
+GlobalData *pG;
+GlobalLocalisationData *pGL;
+String InputBaseName;
+
+int main(int argc, char * argv[])
+	{
+	cout << "\n"; 
+	int vParam=0;
+	bool lParam = false; // used as flag to specify whether checking of localisation comment tags should be performed
+	bool lForce = false; // used as flag to force localisation output even if there are no localisation comments
+	bool lAddDefaults = false; // used as flag to add missing default localisation data to input rss/rpp file, this is not the default behaviour
+	logmemorysetting = 0;
+	unsigned short	pParam = 0;
+	String			DataOutputFileName;
+	String			HeaderOutputFileName;
+	String			MessageSuppressionList;
+	String			BasePath;
+	String			SourceFileName;
+	FILE *			pSourceFile;
+	char*			uidsParameter=NULL;
+	char*			dumpDirectory=NULL;
+	fpos_t			filePositionIndicator;
+	int				i;
+	
+	char *fullcommand = argv[0];
+	std::string s(fullcommand);
+
+	if(argc<=1)
+		{
+		OutputHelp();
+		exit(-1);
+		}
+	else
+		{
+		// Look through arguments for ones beginning with '-?'.
+		for(i = 1; i < argc; i++)
+			{
+			if(* argv[i] == '-')
+				{
+				char * settings = argv[i] + 1;
+			
+				if(strchr(settings, '?') )
+					{
+					OutputHelp();
+					exit(-1);
+					}
+				}
+			}
+
+		for(i = 1; i < argc; i++)
+			{
+			if(* argv[i] == '-')
+				{
+				char * settings = argv[i] + 1;
+			
+				if(* settings == 'o' || * settings == 'O')
+					{
+					DataOutputFileName = (settings + 1);
+					continue;
+					}
+
+				if(* settings == 'm' || * settings == 'M')
+					{
+					MessageSuppressionList = (settings + 1);
+					continue;
+					}
+					
+				if(* settings == 'h' || * settings == 'H')
+					{
+					HeaderOutputFileName = (settings + 1);
+					continue;
+					}
+
+				if(* settings == 'i' || * settings == 'I')
+					{
+					InputBaseName = (settings + 1);
+					String DriveAndDirectory = FileAccess::GetDriveAndDirectory(InputBaseName);
+					BasePath = FileAccess::FullPath(DriveAndDirectory);
+					continue;
+					}
+
+				if(* settings == 's' || * settings == 'S')
+					{
+					SourceFileName = (settings + 1);
+					continue;
+					}
+
+				if(* settings == '{')
+					{
+					uidsParameter = settings + 1;
+					char* temp = strchr(uidsParameter, ',');
+					if ((temp == NULL) || (temp == uidsParameter) || (strchr(temp + 1, ',') != NULL)) // check that there is *one* comma in this parameter (no more and no less), and that it is not the first thing immediately after the '{'
+						{
+						OutputHelp();
+						exit(-1);
+						}
+					*temp = ' ';
+					temp = strchr(uidsParameter, '}');
+					if ((temp == NULL) || (temp[1] != '\0'))
+						{
+						OutputHelp();
+						exit(-1);
+						}
+					*temp = ' ';
+					continue;
+					}
+
+				if(* settings == ':')
+					{
+					dumpDirectory=settings+1;
+					continue;
+					}
+
+				if(strchr(settings, 'u') || strchr(settings, 'U') )
+					{
+					SourceCharacterSet = String::CP1252;
+					TargetCharacterSet = String::Unicode;
+					}
+
+				if(strchr(settings, 'v') || strchr(settings, 'V') )
+					vParam = 1;
+				if(strchr(settings, 'p') || strchr(settings, 'P') )
+					pParam = 1;
+				if(strchr(settings, 'l') || strchr(settings, 'L') )
+					lParam = true;
+				if(strchr(settings, 'f') || strchr(settings, 'F') )
+					lForce = true;
+				if(strchr(settings, 'a') || strchr(settings, 'A') )
+					lAddDefaults = true;
+				}
+			}
+		}
+	if(SourceFileName.Length() == 0)
+		{
+		pSourceFile = stdin;
+		}
+	else 
+		{
+		if((pSourceFile = fopen(SourceFileName.GetAssertedNonEmptyBuffer(), "r") ) == NULL)
+			{
+			cerr << "Failed to open " << SourceFileName << endl;
+			exit(-2);
+			}
+		}
+	//Searchig for BOM signature which if found will be ignored
+
+	unsigned char buffer[3];
+	fread( buffer, sizeof( char ), 3, pSourceFile);
+	
+	if((buffer[0]!=239) && (buffer[1]!=187) && (buffer[2]!=191))
+		{
+		// BOM not found. Set the file-position indicator to 0
+		filePositionIndicator = fpos_t();
+		if(fsetpos(pSourceFile, &filePositionIndicator) !=0)
+			{
+			perror("fsetpos error");
+			} 
+		}	
+	verbose = vParam;
+
+	pG = new GlobalData;
+	if (pG==NULL)
+		exit(-4);
+	
+	Tokenize(MessageSuppressionList);
+
+	pGL = new GlobalLocalisationData;
+	if(pG==NULL)
+		exit(-4);
+
+	pG->WarningMultiExplained = false;
+	pG->FileLineHandler.SetPath(BasePath);
+	
+	#ifdef __TOOLS2__
+	pG->FileLineHandler.SetBase(SourceFileName,0);
+	#endif
+	
+	int ret=ParseSourceFile(pSourceFile, pParam);
+	fclose(pSourceFile);
+	
+	pGL->StoreFinalComment(); // final comment not stored during running of lex and yacc
+	if(lParam && (pGL->LocalisationCommentsExist() || lForce))
+		{
+		pGL->AnalyseLocalisationData();
+		pGL->PrintLocalisationWarnings();
+		if(lAddDefaults)
+			{
+			// only add deafult localisation values to rpp/rss file if the option has been set on the command line
+			if(verbose)
+				{
+				cout << "* Reparsing source file and adding any missing default localisation comments" << endl;
+				}
+			pGL->OutputLocalisedFile(SourceFileName);
+			}
+		}
+	if (ret != 0) 
+		{
+		cerr << "RCOMP failed with code " << ret << endl;
+		exit(ret);
+		}
+	// A successful parse, now generate the output files
+
+	CheckLabels(); // check that all labels are declared and emit suitable warnings if not
+
+	if(DataOutputFileName.Length() != 0)
+		{
+
+
+#ifdef __LINUX__
+
+		std::string totalpath(s.substr( 0, s.rfind("/")+1 ));
+		const char* uidTool = "uidcrc";
+
+#else
+		std::string totalpath(s.substr( 0, s.rfind("\\")+1 ));
+		const char* uidTool = "uidcrc.exe";
+
+#endif
+
+		// Calls the uidcrc tool with the full path to where RCOMP resides in
+		std::string uidpath(uidTool);
+		totalpath += uidpath;
+		
+		// Find and replace all occurences of \ with /
+		std::string searchString( "\\" ); 
+		std::string replaceString( "/" );
+ 		std::string::size_type pos = 0;
+	    	while ( (pos = totalpath.find("\\", pos)) != std::string::npos ) {
+        		totalpath.replace( pos, searchString.size(), replaceString );
+		        pos++;
+		    }
+			
+		const char *uidcrcTool = totalpath.c_str();
+
+		bool thirdUidIsOffset=true;
+		
+		char uidcrcUIDs[3][100];
+		strcpy (uidcrcUIDs[0], "0x101f4a6b");
+
+		if (uidsParameter)
+			{
+			// Command line argument takes precedence 
+			
+			strcpy (uidcrcUIDs[1], strtok (uidsParameter, " "));
+			strcpy (uidcrcUIDs[2], strtok (NULL, " "));
+ 
+			char* const temp = strchr(uidcrcUIDs[2], '*');		
+			if (temp == NULL)
+				{
+				thirdUidIsOffset=false;
+				}
+			}
+		else
+			{
+			// otherwise use values supplied in source
+
+			extern unsigned long Uid2;
+			extern unsigned long Uid3;
+			sprintf(uidcrcUIDs[1], "0x%08lx", Uid2);
+			if (Uid3 != 0)
+				{
+				sprintf(uidcrcUIDs[2], "0x%08lx", Uid3);
+				thirdUidIsOffset=false;
+				}
+			}
+
+
+		if (thirdUidIsOffset)
+			{
+			const unsigned int idOfAnyResource = CurrentId; // *must* be unsigned so that when we right-shift it, the top bit doesn't get propagated if its set (i.e. "negative")
+			sprintf(uidcrcUIDs[2], "0x%08x", idOfAnyResource >> 12); // use the 20 bits derived from the resource file's NAME as the 3rd UID
+			}
+
+		if (verbose)
+			{
+			MOFF; cout << uidcrcTool << " " << uidcrcUIDs[0] << " " << uidcrcUIDs[1] << " " << uidcrcUIDs[2] << " " << DataOutputFileName.GetAssertedNonEmptyBuffer(); cout << endl; MON;
+			}
+
+#ifndef __LINUX__
+		const int error = _spawnlp (_P_WAIT,
+									uidcrcTool,
+									uidcrcTool,
+									uidcrcUIDs[0],
+									uidcrcUIDs[1],
+									uidcrcUIDs[2],
+									DataOutputFileName.GetAssertedNonEmptyBuffer(),
+									NULL);
+#else
+		char uidcrc_params[256];
+		const int ret = snprintf(uidcrc_params,
+					 sizeof(uidcrc_params),
+					 "%s %s %s %s %s",
+					 uidcrcTool,
+					 uidcrcUIDs[0],
+					 uidcrcUIDs[1],
+					 uidcrcUIDs[2],
+					 DataOutputFileName.GetBuffer());
+		if(ret <= 0) {
+			cerr << "Failed to write UIDs to " << DataOutputFileName << endl;
+			exit(ret);
+		}
+		const int error = system(uidcrc_params);
+#endif //__LINUX__
+
+		if(error != 0)
+			{
+			cerr << "Failed to write UIDs to " << DataOutputFileName << endl;
+			exit(error);
+			}
+		RCBinaryStream RSCStream;
+		RSCStream.OpenForAppend(DataOutputFileName);
+		if(! RSCStream.IsOpen())
+			{
+			cerr << "Failed to open " << DataOutputFileName << endl;
+			exit(-2);
+			}
+		WriteResourceFile(RSCStream, pG->Index, thirdUidIsOffset, dumpDirectory);
+		}
+	
+	if(HeaderOutputFileName.Length() != 0)
+		{
+		FILE* RSG;
+		RSG = fopen(HeaderOutputFileName.GetAssertedNonEmptyBuffer(), "w");
+		if(RSG==NULL)
+			{
+			cerr << "Failed to open " << HeaderOutputFileName << endl;
+			exit(-2);
+			}
+		WriteHeaderFile(RSG, pG->Index);
+		fclose(RSG);
+		}
+
+	delete pG;
+	delete pGL;
+
+	return 0;
+	}
+
+
+
+