content: /*******************************************************************************
   * Copyright 2014 Trevor Robinson
   * 
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   * 
   *   http://www.apache.org/licenses/LICENSE-2.0
   * 
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   ******************************************************************************/
  package com.scurrilous.circe.params;
  
  import com.scurrilous.circe.HashParameters;
  
  /**
   * Hash parameters used to define a <a
   * href="http://en.wikipedia.org/wiki/Cyclic_redundancy_check">cyclic redundancy
   * check</a> (CRC). Includes some commonly used sets of parameters.
   */
  public class CrcParameters implements HashParameters {
  
      private final String name;
      private final int bitWidth;
      private final long polynomial;
      private final long initial;
      private final long xorOut;
      private final boolean reflected;
  
      /**
       * Constructs a {@link CrcParameters} with the given parameters.
       * 
       * @param name the canonical name of the CRC function
       * @param bitWidth the width of the CRC function
       * @param polynomial the polynomial in binary form (non-reflected)
       * @param initial the initial value of the CRC register
       * @param xorOut a value XOR'ed with the CRC when it is read
       * @param reflected indicates whether the CRC is reflected (LSB-first)
       * @throws IllegalArgumentException if the width is less than 1 or greater
       *             than 64
       */
      public CrcParameters(String name, int bitWidth, long polynomial, long initial, long xorOut,
              boolean reflected) {
          if (bitWidth < 1 || bitWidth > 64)
              throw new IllegalArgumentException();
          this.name = name;
          this.bitWidth = bitWidth;
          final long mask = bitWidth < 64 ? (1L << bitWidth) - 1 : ~0L;
          this.polynomial = polynomial & mask;
          this.initial = initial & mask;
          this.xorOut = xorOut & mask;
          this.reflected = reflected;
      }
  
      @Override
      public String algorithm() {
          return name;
      }
  
      /**
       * Returns the width in bits of the CRC function. The width is also the
       * position of the implicit set bit at the top of the polynomial.
       * 
       * @return the CRC width in bits
       */
      public int bitWidth() {
          return bitWidth;
      }
  
      /**
       * Returns the binary form of polynomial that defines the CRC function (with
       * the implicit top bit omitted). For instance, the CRC-16 polynomial
       * x<sup>16</sup> + x<sup>15</sup> + x<sup>2</sup> + 1 is represented as
       * {@code 1000 0000 0000 0101} ({@code 0x8005}).
       * 
       * @return the CRC polynomial
       */
      public long polynomial() {
          return polynomial;
      }
  
      /**
       * Returns the initial value of the CRC register.
       * 
       * @return the CRC initial value
       */
      public long initial() {
          return initial;
      }
  
      /**
       * Returns the value XOR'ed with the CRC register when it is read to
       * determine the output value.
       * 
       * @return the final XOR value
       */
      public long xorOut() {
          return xorOut;
      }
  
      /**
       * Returns whether the CRC function is "reflected". Reflected CRCs process
       * data LSB-first, whereas "normal" CRCs are MSB-first.
       * 
       * @return whether the CRC function is reflected
       */
      public boolean reflected() {
          return reflected;
      }
  
      /**
       * Returns whether this object matches the given CRC parameters.
       * 
       * @param bitWidth the width of the CRC function
       * @param polynomial the polynomial in binary form (non-reflected)
       * @param initial the initial value of the CRC register
       * @param xorOut a value XOR'ed with the CRC when it is read
       * @param reflected indicates whether the CRC is reflected (LSB-first)
       * @return true if all parameters match exactly, false otherwise
       */
      public boolean match(int bitWidth, long polynomial, long initial, long xorOut, boolean reflected) {
          return bitWidth == this.bitWidth && polynomial == this.polynomial &&
                  initial == this.initial && xorOut == this.xorOut && reflected == this.reflected;
      }
  
      @Override
      public boolean equals(Object obj) {
          if (this == obj)
              return true;
          if (obj == null || getClass() != obj.getClass())
              return false;
          final CrcParameters other = (CrcParameters) obj;
          return bitWidth == other.bitWidth && polynomial == other.polynomial &&
                  initial == other.initial && xorOut == other.xorOut && reflected == other.reflected;
      }
  
      @Override
      public int hashCode() {
          return (int) (polynomial ^ (polynomial >>> 32) ^ initial ^ (initial >>> 32) ^ xorOut ^ (xorOut >>> 32)) ^
                  (reflected ? ~0 : 0);
      }
  
      /**
       * Parameters for CRC-16, used in the ARC and LHA compression utilities.
       */
      public static final CrcParameters CRC16 = new CrcParameters("CRC-16", 16, 0x8005, 0, 0, true);
  
      /**
       * Parameters for CRC-16/CCITT, used in the Kermit protocol.
       */
      public static final CrcParameters CRC16_CCITT = new CrcParameters("CRC-16/CCITT", 16, 0x1021,
              0, 0, true);
  
      /**
       * Parameters for CRC-16/XMODEM, used in the XMODEM protocol.
       */
      public static final CrcParameters CRC16_XMODEM = new CrcParameters("CRC-16/XMODEM", 16, 0x1021,
              0, 0, false);
  
      /**
       * Parameters for CRC-32, used in Ethernet, SATA, PKZIP, ZMODEM, etc.
       */
      public static final CrcParameters CRC32 = new CrcParameters("CRC-32", 32, 0x04c11db7, ~0, ~0,
              true);
  
      /**
       * Parameters for CRC-32/BZIP2, used in BZIP2.
       */
      public static final CrcParameters CRC32_BZIP2 = new CrcParameters("CRC-32/BZIP2", 32,
              0x04c11db7, ~0, ~0, false);
  
      /**
       * Parameters for CRC-32C, used in iSCSI and SCTP.
       */
      public static final CrcParameters CRC32C = new CrcParameters("CRC-32C", 32, 0x1edc6f41, ~0, ~0,
              true);
  
      /**
       * Parameters for CRC-32/MPEG-2, used in MPEG-2.
       */
      public static final CrcParameters CRC32_MPEG2 = new CrcParameters("CRC-32/MPEG-2", 32,
              0x04c11db7, ~0, 0, false);
  
      /**
       * Parameters for CRC-32/POSIX, used in the {@code cksum} utility.
       */
      public static final CrcParameters CRC32_POSIX = new CrcParameters("CRC-32/POSIX", 32,
              0x04c11db7, 0, ~0, false);
  
      /**
       * Parameters for CRC-64, used in the ECMA-182 standard for DLT-1 tapes.
       */
      public static final CrcParameters CRC64 = new CrcParameters("CRC-64", 64, 0x42f0e1eba9ea3693L,
              0L, 0L, false);
  
      /**
       * Parameters for CRC-64/XZ, used in the {@code .xz} file format.
       */
      public static final CrcParameters CRC64_XZ = new CrcParameters("CRC-64/XZ", 64,
              0x42f0e1eba9ea3693L, ~0L, ~0L, true);
  }
  