/*
 * bin2res.cpp - generate embedded resources from binary data (based on qembed)
 *
 * Copyright (c) 2005-2008 Tobias Doerffel <tobydox/at/users.sourceforge.net>
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public
 * License along with this program (see COPYING); if not, write to the
 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301 USA.
 *
 */


#include <string>
#include <vector>
#include <iostream>
#include <fstream>

static void embedData( const char * _input, int _size, std::ostream & _output );
static std::string convertFileNameToCIdentifier( const std::string & _s );


struct embed
{
	unsigned int size;
	std::string name;
	std::string cname;
} ;

typedef std::vector<std::string> stringlist;

const int MAX_FILE_SIZE = 256*256*256;		// = 16 MB


int main( int argc, char * * argv )
{
	if( argc < 2 )
	{
		std::cerr << "Usage:"  << std::endl << "\t" << argv[0] <<
							" files" << std::endl;
		return( 1 );
	}

	std::cout << "// Generated by bin2res" << std::endl;

	std::vector<embed *> embedded_data;

	std::cout << "#ifndef _EMBEDDED_RESOURCES_H" << std::endl;
	std::cout << "#define _EMBEDDED_RESOURCES_H" << std::endl;

	stringlist files;
	for( int i = 1; i < argc; ++i )
	{
		files.push_back( std::string( argv[i] ) );
	}
	for( stringlist::iterator it = files.begin(); it != files.end(); ++it )
	{
		std::ifstream f( it->c_str(), std::ios::binary );
		if( f.fail() )
		{
			std::cerr << "Cannot open file " << *it <<
						", ignoring it" << std::endl;
			continue;
		}
		f.seekg( 0, std::ios::end );
		int fsize = f.tellg();
		f.seekg( 0 );
		if( fsize == 0 || fsize > MAX_FILE_SIZE )
		{
			std::cerr << "File " << *it << " has zero size or is "
				"too large to be processed with bin2res." <<
								std::endl;
		}
		char * data = new char[fsize];
		f.read( data, fsize );
		embed * e = new embed;
		e->size = fsize;
		if( it->rfind( '/' ) != std::string::npos )
		{
			e->name = std::string( it->c_str() +
							it->rfind( '/' ) + 1 );
		}
		else
		{
			e->name = *it;
		}
		e->cname = convertFileNameToCIdentifier( e->name );
		embedded_data.push_back( e );
		std::string s;
		std::cout << "static const unsigned char " << e->cname <<
								"_data[] = {";
		embedData( data, fsize, std::cout );
		std::cout << std::endl << "};" << std::endl << std::endl;
		delete[] data;
	}

	if( embedded_data.size() > 0 )
	{
		std::cout << "static const unsigned char dummy_data[] ="
					"{ 0x00 };" << std::endl << std::endl;
		embed * dummy = new embed;
		dummy->size = 1;
		dummy->name = "dummy";
		dummy->cname = convertFileNameToCIdentifier(
						std::string( "dummy" ) );
		embedded_data.push_back( dummy );

		std::cout << "#include <string.h>" << std::endl << std::endl;
		std::cout << "#include \"embed.h\"" << std::endl << std::endl;
		std::cout << "static embed::descriptor embed_vec[] = {" << std::endl;
/*				<< "{" << std::endl
				<< "	int size;" << std::endl
				<< "	const unsigned char * data;" <<
								std::endl
				<< "	const char * name;" << std::endl
				<< "} embed_vec[] = {" << std::endl;*/
		while( embedded_data.size() > 0 )
		{
			embed * e = embedded_data[0];
			std::cout << "	{ " << e->size << ", " << e->cname <<
						"_data, " << "\"" << e->name <<
							"\" }," << std::endl;
			delete e;
			embedded_data.erase( embedded_data.begin() );
		}
		std::cout << "	{ 0, 0, 0 }" << std::endl << "};" << std::endl
								<< std::endl
				<< "static const embed::descriptor & "
				   "findEmbeddedData( const char * _name )"
				<< std::endl << "{" << std::endl
				<< "	for( int i = 0; embed_vec[i].data; "
							"i++ )" << std::endl
				<< "	{" << std::endl
				<< "		if( strcmp( embed_vec[i].name, "
						"_name ) == 0 )" << std::endl
				<< "		{" << std::endl
				<< "			return( "
						"embed_vec[i] );" << std::endl
				<< "		}" << std::endl
				<< "	}" << std::endl
/*				<< "	printf( \"warning: embedded resource "
						"%s not found!\\n\", _name );"
								<< std::endl*/
				<< "	return( findEmbeddedData( "
						"\"dummy\" ) );" << std::endl
				<< "}" << std::endl << std::endl;
	}
	std::cout << "#endif" << std::endl;
	return( 0 );
}




std::string convertFileNameToCIdentifier( const std::string & _s )
{
	std::string r = _s;
	int len = r.length();
	if ( len > 0 && !isalpha( (char)r[0] ) )
	{
		r[0] = '_';
	}
	for ( int i = 1; i < len; i++ )
	{
		if ( !isalnum( (char)r[i] ) )
		{
			r[i] = '_';
		}
	}
	return( r );
}




void embedData( const char * _input, int _nbytes, std::ostream & _output )
{
	static const char hexdigits[] = "0123456789abcdef";
	std::string s;
	for( int i = 0; i < _nbytes; i++ )
	{
		if( ( i%14 ) == 0 )
		{
			s += "\n    ";
			_output << s;
			s = "";
		}
		unsigned int v = _input[i];
		s += "0x";
		s += hexdigits[(v >> 4) & 15];
		s += hexdigits[v & 15];
		if( i < _nbytes-1 )
		{
			s += ',';
		}
	}
	if ( s.length() )
	{
		_output << s;
	}
}

