/* bareos-check-sources:disable-copyright-check */
/******************************************************************************/
/*                             Start of crcmodel.c                            */
/******************************************************************************/
/*                                                                            */
/* Author : Ross Williams (ross@guest.adelaide.edu.au.).                      */
/* Date   : 3 June 1993.                                                      */
/* Status : Public domain.                                                    */
/*                                                                            */
/* Description : This is the implementation (.c) file for the reference       */
/* implementation of the Rocksoft^tm Model CRC Algorithm. For more            */
/* information on the Rocksoft^tm Model CRC Algorithm, see the document       */
/* titled "A Painless Guide to CRC Error Detection Algorithms" by Ross        */
/* Williams (ross@guest.adelaide.edu.au.). This document is likely to be in   */
/* "ftp.adelaide.edu.au/pub/rocksoft".                                        */
/*                                                                            */
/* Note: Rocksoft is a trademark of Rocksoft Pty Ltd, Adelaide, Australia.    */
/*                                                                            */
/******************************************************************************/
/*                                                                            */
/* Implementation Notes                                                       */
/* --------------------                                                       */
/* To avoid inconsistencies, the specification of each function is not echoed */
/* here. See the header file for a description of these functions.            */
/* This package is light on checking because I want to keep it short and      */
/* simple and portable (i.e. it would be too messy to distribute my entire    */
/* C culture (e.g. assertions package) with this package.                     */
/*                                                                            */
/******************************************************************************/

#include "droplet/cdmi/crcmodel.h"

/******************************************************************************/

/* The following definitions make the code more readable. */

#define BITMASK(X) (1L << (X))
#define MASK32 0xFFFFFFFFL
#define LOCAL static

/******************************************************************************/

LOCAL ulong reflect P_((ulong v, int b));
/* Returns the value v with the bottom b [0,32] bits reflected. */
/* Example: reflect(0x3e23L,3) == 0x3e26                        */
LOCAL ulong reflect(ulong v, int b)
{
  int i;
  ulong t = v;
  for (i = 0; i < b; i++) {
    if (t & 1L)
      v |= BITMASK((b - 1) - i);
    else
      v &= ~BITMASK((b - 1) - i);
    t >>= 1;
  }
  return v;
}

/******************************************************************************/

LOCAL ulong widmask P_((p_cm_t));
/* Returns a longword whose value is (2^p_cm->cm_width)-1.     */
/* The trick is to do this portably (e.g. without doing <<32). */
LOCAL ulong widmask(p_cm_t p_cm)
{
  return (((1L << (p_cm->cm_width - 1)) - 1L) << 1) | 1L;
}

/******************************************************************************/

void cm_ini(p_cm_t p_cm) { p_cm->cm_reg = p_cm->cm_init; }

/******************************************************************************/

void cm_nxt(p_cm_t p_cm, int ch)
{
  int i;
  ulong uch = (ulong)ch;
  ulong topbit = BITMASK(p_cm->cm_width - 1);

  if (p_cm->cm_refin) uch = reflect(uch, 8);
  p_cm->cm_reg ^= (uch << (p_cm->cm_width - 8));
  for (i = 0; i < 8; i++) {
    if (p_cm->cm_reg & topbit)
      p_cm->cm_reg = (p_cm->cm_reg << 1) ^ p_cm->cm_poly;
    else
      p_cm->cm_reg <<= 1;
    p_cm->cm_reg &= widmask(p_cm);
  }
}

/******************************************************************************/

void cm_blk(p_cm_t p_cm, p_ubyte_ blk_adr, ulong blk_len)
{
  while (blk_len--) cm_nxt(p_cm, *blk_adr++);
}

/******************************************************************************/

ulong cm_crc(p_cm_t p_cm)
{
  if (p_cm->cm_refot)
    return p_cm->cm_xorot ^ reflect(p_cm->cm_reg, p_cm->cm_width);
  else
    return p_cm->cm_xorot ^ p_cm->cm_reg;
}

/******************************************************************************/

ulong cm_tab(p_cm_t p_cm, int index)
{
  int i;
  ulong r;
  ulong topbit = BITMASK(p_cm->cm_width - 1);
  ulong inbyte = (ulong)index;

  if (p_cm->cm_refin) inbyte = reflect(inbyte, 8);
  r = inbyte << (p_cm->cm_width - 8);
  for (i = 0; i < 8; i++)
    if (r & topbit)
      r = (r << 1) ^ p_cm->cm_poly;
    else
      r <<= 1;
  if (p_cm->cm_refin) r = reflect(r, p_cm->cm_width);
  return r & widmask(p_cm);
}

/******************************************************************************/
/*                             End of crcmodel.c                              */
/******************************************************************************/
