// endianConversion.cc  P. Conrad   Fall 2005 for CISC181
// test some routines for converting to Little Endian

#include <iostream>
#include <iomanip>
using namespace std;


bool systemIsLittleEndian()
{
  int x=65;
  int * addressOfX = &x;  // addressOfX is the location of x in memory

  // int * is a type that means "a pointer to an integer".
  // an int * can be used as any of the following:
  //     (a) a pointer to an integer
  //     (b) the address of an integer
  //     (c) the name of an array of integers [more on that later]
  
  char c[4];


  // Note that the name of an array (e.g. c) refers to the address in 
  // memory where that array "lives".  So an array name like c
  // is also a (char *), or "pointer to character".  It can be considered
  //   (a) a pointer to a character (the element [0] in the array)
  //   (b) the address of a character (the element [0] in the array)
  //   (c) the name of an array of characters.

  // The memcpy() function will copy four bytes from where X lives 
  // into the array called c.   

  // (void *) means "generic pointer"; it converts a particular kind of
  // address (e.g. (int *) or (char *) into a "generic address".
  // C++ would normally complain about us "mixing types".   Type casting
  // (putting (void *) in front of an expression) signals the compiler
  // that we "know what we are doing" and are accepting the consequences.

  memcpy((void *) c, (void *) addressOfX, 4);  

  if ( c[0] == '\0' &&  c[1] == '\0' &&  c[2] == '\0' &&  c[3] == 'A')
    {
      return false;
    }
  else if ( c[0] == 'A' &&  c[1] == '\0' &&  c[2] == '\0' &&  c[3] == '\0')
    {
      return true;
    }
  else
    {
      cerr << "I can't tell is your system is big or little endian" << endl;
      cerr << "Something is probably wrong with the program." << endl;
      exit(1);
    }
}

int convertToLittleEndian(int x)
{
  if (systemIsLittleEndian())
    return x;

  char c[4];
  memcpy((void *) c, (void *) &x, 4);

  char temp = c[0];
  c[0] = c[3];
  c[3] = temp;

  temp = c[2];
  c[2] = c[1];
  c[1] = temp;

  memcpy((void *) &x, (void *) c, 4);

  return x;
      
}

signed short convertShortToLittleEndian(signed short x)
{
  if (systemIsLittleEndian())
    return x;

  char c[2];
  memcpy((void *) c, (void *) &x, 2);

  char temp = c[0];
  c[0] = c[1];
  c[1] = temp;

  memcpy((void *) &x, (void *) c, 2);

  return x;

}



int main(void)
{
  int x = 0x87654321;
  signed short y = 0x4321;

  cout << "host order,    x=" << hex << setw(8) << x  
       << " host order,     y=" << hex << setw(8) << y << endl;
 
  cout << "little endian, x=" << hex << setw(8) 
       << convertToLittleEndian(x);

  cout << " little endian,  y=" << hex << setw(8) 
       << convertShortToLittleEndian(y) << endl;

}



