// Time-stamp: "02.12.10 11:58 bin2c.cpp klaus?wachtler.de"
//
// reads one or more files and outputs their content as C array
// initializers.
//
// The resulting file (eg. "test.bin.c") may be used like:
//  const char my_test_array[]
//     = {
//  #include "test.bin.c"
//       };
// The generated files contain no {} and end with an colon, so there
// may be more than one file to initalize an array:
//  const char my_test_array[]
//     = {
//  #include "test.bin1.c"
//  #include "test.bin2.c"
//  #include "test.bin3.c"
//       };
//
// There will be no automatically added trailing zero neither any other
// special treatment of zeroes
//
// Compile this file like:
//    cl /EHsc  bin2c.cpp             (Windows, VS2005)
//    g++ -Wall bin2c.cpp -o bin2c    (GNU systems/Linux)

#define N_CHARS_PER_LINE    (16)

#define _CRT_SECURE_NO_DEPRECATE   1

#include <iostream>
#include <cctype>
#include <fstream>
#include <string>
#include <iomanip>
#include <ctime>
#include <cstring>

void usage( const char *name )
{
  std::cout << name << std::endl;
  std::cout << "This tool converts any files to C source as initializer" << std::endl;
  std::cout << "for char arrays." << std::endl;
  std::cout << "No surrounding {} are written." << std::endl;
  std::cout << "" << std::endl;
  std::cout << "Usage: " << std::endl;
  std::cout << name << " file [file2 [file3...]]" << std::endl;
  std::cout << "" << std::endl;
  std::cout << "The output files have the name of the given" << std::endl;
  std::cout << "input files with .c appended." << std::endl;
  std::cout << "" << std::endl;
  std::cout << "05.01.2009 Klaus Wachtler" << std::endl;
}

void binToC( const char *name )
{
  std::ifstream    input( name );
  std::ofstream    output( ( std::string( name ) + ".c" ).c_str() );
  size_t           count   = 0;
  char             c;

  // write starting comment
  time_t           timeAktuell = time( NULL );
  struct tm        tmAktuell;
  tmAktuell = *localtime( &timeAktuell );
  output << "    // " << name << " generated " << std::dec
         << std::setfill( '0'  ) << std::setw( 2 ) << tmAktuell.tm_mday
         << '.'
         << std::setfill( '0'  ) << std::setw( 2 ) << ( tmAktuell.tm_mon + 1 )
         << '.'
         << std::setfill( '0'  ) << std::setw( 4 ) << ( tmAktuell.tm_year + 1900 )
         << ' '
         << std::setfill( '0'  ) << std::setw( 2 ) << tmAktuell.tm_hour
         << ':'
         << std::setfill( '0'  ) << std::setw( 2 ) << tmAktuell.tm_min
         << ':'
         << std::setfill( '0'  ) << std::setw( 2 ) << tmAktuell.tm_sec
         << " by " << __FILE__ << std::endl;

  while( input.get( c ) )
  {
    if( ( count%N_CHARS_PER_LINE )==0 )
    {
      output << "    ";
    }
    count++;

    if( isprint( c ) )
    {
      if( std::strchr( "\'\\\"", c ) )
      {
        // quote character!
        output << "\'\\" << c << '\'' << ',';
      }
      else
      {
        // write unquoted:
        output << '\'' << c << '\'' << ',';
      }
    }
    else
    {
      // not printable? write hex representation
      output << "0x" << std::hex << std::setfill( '0'  ) << (int)c << ',';
    }
    // write new line from time to time
    if( ( count%N_CHARS_PER_LINE )==0 )
    {
      output << std::endl;
    }
  }
  output << std::endl;
}

int main( int nargs, char **args )
{
  if( nargs<=1 )
  {
    usage( args[0] );
    return 0;
  }

  for( int iArgs=1; iArgs<nargs; ++iArgs )
  {
    binToC( args[iArgs] );
  }

  return 0;
}
