/* Program to encode two strings concerning elephants.
   Author: M.V.Wickerhauser
   Date: 21 August 2002
*/

#include <stdio.h>

int
write_bits( const char *msg )
{
  int i, b, letter, parity, bit[8];

  if(!msg) return 0;		/* Exit at NULL input */
  puts(msg);
  i=0;
  while(msg[i]) {		/* stop at terminating NULL */
    letter = msg[i];		/* assumes ASCII internal coding */
    parity = 0;
    for(b=6; b>=0; b--) {
      bit[b] = (letter>>b)&1;
      parity += bit[b];
    }
    bit[7] = parity&1;		/* preserves even parity */
    for(b=7; b>=0; b--)
      printf("%1d",bit[b]);
    putchar(' ');
    ++i;
    if(i%8 == 0) putchar('\n');
  }
  puts(" (base 2)");
  return i;
}

int
write_hex( const char *msg )
{
  int i, b, letter, parity;

  if(!msg) return 0;		/* Exit at NULL input */
  puts(msg);
  i=0;
  while(msg[i]) {		/* stop at terminating NULL */
    letter = msg[i];		/* assumes ASCII internal coding */
    parity = 0;
    for(b=0; b<7; b++) parity += (letter>>b)&1;
    letter |= (parity&1)<<7;	/* preserves even parity */
    printf("%2X ", letter);
    ++i;
    if(i%24==0) putchar('\n');
  }
  puts(" (base 16)");
  return i;
}

int
all_bits( int *allbits,  const char *msg )
{
  int i, n, b, letter, parity, bit[8];

  if(!msg) return 0;		/* Exit at NULL input */
  if(!allbits) exit(1);		/* Crash at NULL output */
  n=0;				/* Number of bits written */
  for(i=0; msg[i]; i++) {	/* Stop reading at terminating NULL */
    letter = msg[i];		/* Assume ASCII internal coding */
    parity = 0;
    for(b=6; b>=0; b--) {
      bit[b] = (letter>>b)&1;
      parity += bit[b];
    }
    bit[7] = parity&1;		/* preserves even parity */
    for(b=7; b>=0; b--) allbits[n++] = bit[b];
  }
  return n;
}

int
print_all( const int *allbits,  int numbits )
{
  int  n;
  if(!allbits || !numbits ) return 0;	/* Exit at NULL input */
  for(n=0; n<numbits; n++) {
    printf("%d",allbits[n]);
    if((n+1)%8==0) putchar(' ');
    if((n+1)%64==0) putchar('\n');
  }
  puts(" (base 2)");
  return n;
}

int
mod2mod( int *msgbit, int numbits, int *mod2poly, int deg )
{
  int checksum, d, n;

  for(n=0; n<numbits-deg; n++ )
    if( msgbit[n]==1 )		/* ...then XOR with the  mod-2 polynomial */
      for(d=0; d<=deg; d++)
	msgbit[n+d] ^= mod2poly[deg-d];
  for(checksum=0; n<numbits; n++)
    checksum = 2*checksum + msgbit[n]; 
  return checksum;
}

int
main()
{
  const char msg1[]="Elephants are approaching from the South!";
  const char msg2[]="Elephants are approaching from the North!";
  const char msg3[]="Elephants are approaching from the NORTH!";
  int all1[41*8]={0}, all2[41*8]={0}, all3[41*8]={0};
  int n1, n2, n3, cs1, cs2, cs3;
  int modulus[]={1,1,0,1};	/* 1+t+t^3; Degree 3, with 4 terms. */

  write_bits(msg1);
  n1 = all_bits( all1, msg1 );
  print_all(all1, n1);
  write_hex(msg1);
  cs1 = mod2mod( all1, n1, modulus, 3);
  printf("--> checksum is %d\n\n", cs1 );

  write_bits(msg2);
  n2 = all_bits( all2, msg2 );
  print_all(all2, n2);
  write_hex(msg2);
  cs2 = mod2mod( all2, n2, modulus, 3);
  printf("--> checksum is %d\n\n", cs2 );

  write_bits(msg3);
  n3 = all_bits( all3, msg3 );
  print_all(all3, n3);
  write_hex(msg3);
  cs3 = mod2mod( all3, n3, modulus, 3);
  printf("--> checksum is %d\n\n", cs3 );


  return 0;
}
