
/*
Copyright 2004-2011 Herbert Street Technologies Ltd
*/

function Int64( l, h ) 
{ 
  this.H = h == undefined ? 0 : h ;
  this.L = l == undefined ? 0 : l ; 
  this.ToString = toString ;
  this.Shift1 = shift1 ;
  this.Shift8 = shift8 ;
  this.Xor = xor ;
  function toString()
  {
    function w2x( w )
    {
      var x = w.toString( 16 ) ;
      for( var i = 4 - x.length ; i > 0 ; i-- ) x = '0' + x ;
      return x ;
    }
    function l2x( i )
    {
      return w2x( ( i >> 16 ) & 0xFFFF ) + w2x( i & 0xFFFF ) ;
    }
    return l2x( this.H ) + l2x( this.L ) ;
  }
  function shift1()
  {
    var l = this.L, h = this.H, b = l & 0x1 ;
    this.L = ( ( l >> 1 ) & 0x7FFFFFFF ) | ( ( h & 0x1 ) << 31 ) ;
    this.H = ( h >> 1 ) & 0x7FFFFFFF ;
    return b ;
  }
  function shift8()
  {
    var l = this.L, h = this.H, b = l & 0xFF ;
    this.L = ( ( l >> 8 ) & 0xFFFFFF ) | ( ( h & 0xFF ) << 24 ) ;
    this.H = ( h >> 8 ) & 0xFFFFFF ;
    return b ;
  }
  function xor( i )
  {
    this.L = this.L ^ i.L ;
    this.H = this.H ^ i.H ;
    return this ;
  }
}

function CRC64()
{
  this.Create = create ;
  this.XXCreate = xxCreate ;
  this.T = initTable() ;

  function initTable() 
  {
    var t = new Array( 256 ), poly = new Int64( 0xD7870F42, 0xC96C5795 ) ;
    for( var i = 0 ; i < 256 ; i++ ) {
      var v = new Int64( i ) ;
      for( var j = 0 ; j < 8 ; j++ ) if( v.Shift1() != 0 ) v.Xor( poly ) ;
      t[ i ] = v ;
    }
    return t ;
  }

  function create( crc, b )
  {
    var ff = new Int64( 0xffffffff, 0xffffffff ) ; 
    crc.Xor( ff ) ;
    for( var i = 0, l = b.length ; i < l ; i++ ) {
      crc.Xor( this.T[ ( crc.Shift8() ^ b[ i ] ) & 0xFF ] ) ; 
    }
    return crc.Xor( ff ) ;
  }
  function xxCreate( crc, b ) { return this.Create( crc, b ).ToString() ; }
}




