Milán Major

netscape-revival

1 branch
Code

security/lib/crypto/cmpbits.c

/* Copyright (C) RSA Data Security, Inc. created 1995.  This is an
   unpublished work protected as such under copyright law.  This work
   contains proprietary, confidential, and trade secret information of
   RSA Data Security, Inc.  Use, disclosure or reproduction without the
   express written authorization of RSA Data Security, Inc. is
   prohibited.
 */

/* This file contains routines that manipulate bits.
 */
#include "crypto.h"
#include "cmp.h"
#include "cmppriv.h"
#include "cmpspprt.h"

/* This routine determines how long, in bits, a CMPInt is.
 */
int
CMP_BitLengthOfCMPInt(CMPInt *theInt)
{
  register int bitIndex, mswIndex;
  register CMPWord temp;

#ifdef CMP_DEBUG
  if (CMP_PINT_LENGTH (theInt) <=0)
    return (CMP_LENGTH);
#endif

  if (CMP_PINT_VALUE (theInt) != CMP_NULL_VALUE) {
    bitIndex = 1;
    mswIndex = CMP_PINT_LENGTH (theInt) - 1;
    temp = CMP_PINT_WORD (theInt, mswIndex) >> 1;  
    while (temp > 0) {
      bitIndex++;
      temp >>= 1;
    }
    return ((mswIndex * CMP_WORD_SIZE) + bitIndex);
  }
  /* If theInt is a constructed CMPInt, but has nothing in it,
       return 0. */
  return (0);
}

/* Gets the bitPosition-th bit of theInt, setting the return variable
     theBit to 1 or 0, depending on whether the bitPosition-th bit is
     set or not.
 */
CMPStatus
CMP_GetBit(int bitPosition, CMPInt *theInt, int *theBit)
{
  int wordIndex, bitIndex;

#ifdef CMP_DEBUG
  if (CMP_PINT_VALUE (theInt) == CMP_NULL_VALUE)
    return (CMP_INVALID_ADDRESS);
  if (CMP_PINT_LENGTH (theInt) <= 0)
    return (CMP_LENGTH);
  if (bitPosition < 0)
    return (CMP_INVALID_ARGUMENT);
#endif

  wordIndex = bitPosition / CMP_WORD_SIZE;
  bitIndex  = bitPosition % CMP_WORD_SIZE;

  if (wordIndex < CMP_PINT_LENGTH (theInt)) {
    *theBit = (int)((CMP_PINT_WORD (theInt, wordIndex) >> bitIndex) & 1);
    return(CMP_SUCCESS);
  }

  /* Getting a bit beyond the current most significant word of theInt,
       by definition, such a bit is 0. */
  *theBit = 0;
  return (CMP_SUCCESS);
}

/* Clears (sets to 0) the bitPosition-th bit of theInt.
 */
CMPStatus
CMP_ClearBit(int bitPosition, CMPInt *theInt)
{
  int wordIndex, bitIndex;

#ifdef CMP_DEBUG
  if (CMP_PINT_VALUE (theInt) != CMP_NULL_VALUE)
    return (CMP_INVALID_ADDRESS);
  if (CMP_PINT_LENGTH (theInt) < 0)
    return (CMP_LENGTH);
  if (bitPosition < 0)
    return (CMP_INVALID_ARGUMENT);
#endif

  wordIndex = bitPosition / CMP_WORD_SIZE;
  bitIndex  = bitPosition % CMP_WORD_SIZE;

  /* If the length is not greater than the wordIndex, we're trying to
       clear a bit beyond the ms word.
   */
  if (CMP_PINT_LENGTH (theInt) > wordIndex) {
    CMP_PINT_WORD (theInt, wordIndex) &=
      CMP_WORD_MASK ^ ((CMPWord)1 << bitIndex);
    CMP_RecomputeLength (CMP_PINT_LENGTH (theInt) - 1, theInt);
    return(CMP_SUCCESS);
  }

  /* Clearing a bit beyond the ms word of theInt, such a bit, by
       definition, is already clear. */
  return (CMP_SUCCESS);
}

/* Sets (to 1) the bitPosition-th bit of theInt.
 */
CMPStatus
CMP_SetBit(int bitPosition, CMPInt *theInt)
{
  int wordIndex, bitIndex;
  CMPStatus status;

#ifdef CMP_DEBUG
  if (CMP_PINT_LENGTH (theInt) <= 0)
    return (CMP_LENGTH);
  if (bitPosition < 0)
    return (CMP_INVALID_ARGUMENT);
#endif

  wordIndex = bitPosition / CMP_WORD_SIZE;
  bitIndex  = bitPosition % CMP_WORD_SIZE;

  if (wordIndex < CMP_PINT_LENGTH (theInt)) {
    CMP_PINT_WORD (theInt, wordIndex) |= ((CMPWord)1 << bitIndex);
    return(CMP_SUCCESS);
  }

  /* Setting a bit beyond the current most significant word of theInt.
   */
  if (CMP_PINT_SPACE (theInt) < wordIndex + 1)
    if ((status = CMP_realloc (wordIndex + 2, theInt)) != 0)
      return (status);

  /* Set all the new words to 0. */
  PORT_Memset((unsigned char *)&CMP_PINT_WORD(theInt, CMP_PINT_LENGTH (theInt)),
	      0, (CMP_PINT_SPACE (theInt) - CMP_PINT_LENGTH (theInt)) *
	      CMP_BYTES_PER_WORD);

  /* Set the bit. */
  CMP_PINT_WORD (theInt, wordIndex) = ((CMPWord)1 << bitIndex);
  CMP_RecomputeLength (wordIndex, theInt);

  return (CMP_SUCCESS);
}