/*
    player-convert.c

    player/global database conversion utility.  Converts both the global and
    the player database between endian architectures (i.e.,
    Intel<->anything else.

    Usage: player-convert <orig global> <orig player> <new global> <new player>

    Note that it doesn't make any difference which way the conversion is
    going (big endian to little endian, or vice versa).  Since the conversion
    simply involves a byte-swap, it is its own inverse.  Running this program
    twice on the databases will result in the original databases.

    This program falls under that copyright included with the rest of the
    Paradise code (which I am too lazy to reproduce here).

    Oh, and one more thing:  this program has the unfortunate job of 
    translating floats as well.  This works as long as the machines are 
    IEEE 754/854 compliant (most are.  Crays, at last check, weren't).

    Also, this program will only convert between 32-bit architectures.
    If you're running a server with a different word length, this program
    is pretty much guaranteed not to work.
  
    Bob Glamm (June 26, 1995)
*/

#include <stdio.h>
#include <sys/fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "defs.h"
#include "struct.h"

/* 
   No, I've never heard of byteorder.h.  And neither have you. ;)
   Deal with it. 
*/ 

void swap( unsigned char *, unsigned char * );
void do_global( char *, char * );
void do_players( char *, char * );

#define SWAP(a,b) swap(&(a),&(b))
#define SWAPBYTES(a) SWAP(a.bytes[0],a.bytes[3]);SWAP(a.bytes[1],a.bytes[2])

typedef union tagWORD{
  unsigned int word;
  float real;
  unsigned char bytes[4];
} word;

int main( int argc, char *argv[] ){

  if( argc != 5 ){
    printf( "Usage: %s <original db.global> <original db.players>\n\t<new db.global> <new db.players>\n", argv[0] );
    exit( 1 );
  }

  do_global( argv[1], argv[3] );
  do_players( argv[2], argv[4] );
}

void swap( unsigned char *a, unsigned char *b ){

  unsigned char t;

  t = *a;
  *a = *b;
  *b = t;
}

#define FIXGLOBAL(a) cvt.word=(a);SWAPBYTES(cvt);(a)=cvt.word;

void do_global( char *infile, char *outfile ){

  int ifile, ofile;
  word cvt;
  struct status stats;

  ifile = open( infile, O_RDWR, 0744 );
  if( ifile < 0 ){
    fprintf( stderr, "Could not open original db.global (%s)\n", infile );
    return;
  }
  ofile = open( outfile, O_RDWR | O_CREAT, 0744 );
  if( ofile < 0 ){
    fprintf( stderr, "Could not open new db.global (%s)\n", outfile );
    close( ifile );
    return;
  }

  if( read( ifile, (char *)(&stats), sizeof( struct status ) ) != sizeof( struct status ) ){
    fprintf( stderr, "Size of original db.global is incompatible with this version of Paradise.\n" );
    close( ofile );
    close( ifile );
    return;
  }

  FIXGLOBAL(stats.active);
  FIXGLOBAL(stats.wait);
  FIXGLOBAL(stats.count);
  FIXGLOBAL(stats.number);
  FIXGLOBAL(stats.request);
  FIXGLOBAL(stats.answer);
  FIXGLOBAL(stats.tourn);
  FIXGLOBAL(stats.dooshes);
  FIXGLOBAL(stats.armsbomb);
  FIXGLOBAL(stats.resbomb);
  FIXGLOBAL(stats.planets);
  FIXGLOBAL(stats.kills);
  FIXGLOBAL(stats.losses);
  FIXGLOBAL(stats.genocides);
  FIXGLOBAL(stats.sbkills);
  FIXGLOBAL(stats.sblosses);
  FIXGLOBAL(stats.sbtime);
  FIXGLOBAL(stats.wbkills);
  FIXGLOBAL(stats.wblosses);
  FIXGLOBAL(stats.wbtime);
  FIXGLOBAL(stats.jsplanets);
  FIXGLOBAL(stats.jstime);
  FIXGLOBAL(stats.time);
  FIXGLOBAL(stats.timeprod);
  FIXGLOBAL(stats.clock);
  FIXGLOBAL(stats.nukegame);
  FIXGLOBAL(stats.gameup);

  write(ofile, (char *)(&stats), sizeof( struct status ) );
  close( ofile );
  close( ifile );
}

#define FIXPLAYER(a) cvt.word=(a);SWAPBYTES(cvt);(a)=cvt.word
#define FIXFLOAT(a) cvt.real=(a);SWAPBYTES(cvt);(a)=cvt.real

void do_players( char *infile, char *outfile ){

  int ifile, ofile;
  word cvt;
  struct statentry *db;
  struct stat fstats;
  int np;
  int bytes;
  int i;

  ifile = open( infile, O_RDWR, 0744 );
  if( ifile < 0 ){
    fprintf( stderr, "Cannot open original db.players (%s)", infile );
    return;
  }
  ofile = open( outfile, O_RDWR | O_CREAT, 0744 );
  if( ofile < 0 ){
    fprintf( stderr, "Cannot open new db.players." );
    close( ifile );
    return;
  }

  fstat( ifile, &fstats );
  np = fstats.st_size/sizeof( struct statentry );
  db = malloc( sizeof( struct statentry ) * np );
  bytes = read( ifile, (char *)db, sizeof( struct statentry )*np );
  if( bytes != sizeof(struct statentry)*np ){
    fprintf( stderr, "Could not read db.players.\n" );
    close( ifile );
    close( ofile );
    return;
  }

  for( i = 0; i < np; i++ ){
    FIXPLAYER(db[i].stats.st_genocides);
    FIXFLOAT(db[i].stats.st_tmaxkills);
    FIXFLOAT(db[i].stats.st_di);
    FIXPLAYER(db[i].stats.st_tkills);
    FIXPLAYER(db[i].stats.st_tlosses);
    FIXPLAYER(db[i].stats.st_tarmsbomb);
    FIXPLAYER(db[i].stats.st_tresbomb);
    FIXPLAYER(db[i].stats.st_tdooshes);
    FIXPLAYER(db[i].stats.st_tplanets);
    FIXPLAYER(db[i].stats.st_tticks);
    FIXPLAYER(db[i].stats.st_sbkills);
    FIXPLAYER(db[i].stats.st_sblosses);
    FIXPLAYER(db[i].stats.st_sbticks);
    FIXFLOAT(db[i].stats.st_sbmaxkills);
    FIXPLAYER(db[i].stats.st_wbkills);
    FIXPLAYER(db[i].stats.st_wblosses);
    FIXPLAYER(db[i].stats.st_wbticks);
    FIXFLOAT(db[i].stats.st_wbmaxkills);
    FIXPLAYER(db[i].stats.st_jsplanets);
    FIXPLAYER(db[i].stats.st_jsticks);
    FIXPLAYER(db[i].stats.st_lastlogin);
    FIXPLAYER(db[i].stats.st_flags);
    FIXPLAYER(db[i].stats.st_cluesuccess);
    FIXPLAYER(db[i].stats.st_rank);
    FIXPLAYER(db[i].stats.st_royal);
  }

  write( ofile, (char *)db, sizeof( struct statentry )*np );
  close( ifile );
  close( ofile );
}
