Blame mpz/export.c

Packit 5c3484
/* mpz_export -- create word data from mpz.
Packit 5c3484
Packit 5c3484
Copyright 2002, 2003, 2012 Free Software Foundation, Inc.
Packit 5c3484
Packit 5c3484
This file is part of the GNU MP Library.
Packit 5c3484
Packit 5c3484
The GNU MP Library is free software; you can redistribute it and/or modify
Packit 5c3484
it under the terms of either:
Packit 5c3484
Packit 5c3484
  * the GNU Lesser General Public License as published by the Free
Packit 5c3484
    Software Foundation; either version 3 of the License, or (at your
Packit 5c3484
    option) any later version.
Packit 5c3484
Packit 5c3484
or
Packit 5c3484
Packit 5c3484
  * the GNU General Public License as published by the Free Software
Packit 5c3484
    Foundation; either version 2 of the License, or (at your option) any
Packit 5c3484
    later version.
Packit 5c3484
Packit 5c3484
or both in parallel, as here.
Packit 5c3484
Packit 5c3484
The GNU MP Library is distributed in the hope that it will be useful, but
Packit 5c3484
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
Packit 5c3484
or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
Packit 5c3484
for more details.
Packit 5c3484
Packit 5c3484
You should have received copies of the GNU General Public License and the
Packit 5c3484
GNU Lesser General Public License along with the GNU MP Library.  If not,
Packit 5c3484
see https://www.gnu.org/licenses/.  */
Packit 5c3484
Packit 5c3484
#include <stdio.h>  /* for NULL */
Packit 5c3484
#include "gmp.h"
Packit 5c3484
#include "gmp-impl.h"
Packit 5c3484
#include "longlong.h"
Packit 5c3484
Packit 5c3484
Packit 5c3484
#if HAVE_LIMB_BIG_ENDIAN
Packit 5c3484
#define HOST_ENDIAN     1
Packit 5c3484
#endif
Packit 5c3484
#if HAVE_LIMB_LITTLE_ENDIAN
Packit 5c3484
#define HOST_ENDIAN     (-1)
Packit 5c3484
#endif
Packit 5c3484
#ifndef HOST_ENDIAN
Packit 5c3484
static const mp_limb_t  endian_test = (CNST_LIMB(1) << (GMP_LIMB_BITS-7)) - 1;
Packit 5c3484
#define HOST_ENDIAN     (* (signed char *) &endian_test)
Packit 5c3484
#endif
Packit 5c3484
Packit 5c3484
void *
Packit 5c3484
mpz_export (void *data, size_t *countp, int order,
Packit 5c3484
	    size_t size, int endian, size_t nail, mpz_srcptr z)
Packit 5c3484
{
Packit 5c3484
  mp_size_t      zsize;
Packit 5c3484
  mp_srcptr      zp;
Packit 5c3484
  size_t         count, dummy;
Packit 5c3484
  unsigned long  numb;
Packit 5c3484
  unsigned       align;
Packit 5c3484
Packit 5c3484
  ASSERT (order == 1 || order == -1);
Packit 5c3484
  ASSERT (endian == 1 || endian == 0 || endian == -1);
Packit 5c3484
  ASSERT (nail <= 8*size);
Packit 5c3484
  ASSERT (nail <  8*size || SIZ(z) == 0); /* nail < 8*size+(SIZ(z)==0) */
Packit 5c3484
Packit 5c3484
  if (countp == NULL)
Packit 5c3484
    countp = &dummy;
Packit 5c3484
Packit 5c3484
  zsize = SIZ(z);
Packit 5c3484
  if (zsize == 0)
Packit 5c3484
    {
Packit 5c3484
      *countp = 0;
Packit 5c3484
      return data;
Packit 5c3484
    }
Packit 5c3484
Packit 5c3484
  zsize = ABS (zsize);
Packit 5c3484
  zp = PTR(z);
Packit 5c3484
  numb = 8*size - nail;
Packit 5c3484
  MPN_SIZEINBASE_2EXP (count, zp, zsize, numb);
Packit 5c3484
  *countp = count;
Packit 5c3484
Packit 5c3484
  if (data == NULL)
Packit 5c3484
    data = (*__gmp_allocate_func) (count*size);
Packit 5c3484
Packit 5c3484
  if (endian == 0)
Packit 5c3484
    endian = HOST_ENDIAN;
Packit 5c3484
Packit 5c3484
  align = ((char *) data - (char *) NULL) % sizeof (mp_limb_t);
Packit 5c3484
Packit 5c3484
  if (nail == GMP_NAIL_BITS)
Packit 5c3484
    {
Packit 5c3484
      if (size == sizeof (mp_limb_t) && align == 0)
Packit 5c3484
	{
Packit 5c3484
	  if (order == -1 && endian == HOST_ENDIAN)
Packit 5c3484
	    {
Packit 5c3484
	      MPN_COPY ((mp_ptr) data, zp, (mp_size_t) count);
Packit 5c3484
	      return data;
Packit 5c3484
	    }
Packit 5c3484
	  if (order == 1 && endian == HOST_ENDIAN)
Packit 5c3484
	    {
Packit 5c3484
	      MPN_REVERSE ((mp_ptr) data, zp, (mp_size_t) count);
Packit 5c3484
	      return data;
Packit 5c3484
	    }
Packit 5c3484
Packit 5c3484
	  if (order == -1 && endian == -HOST_ENDIAN)
Packit 5c3484
	    {
Packit 5c3484
	      MPN_BSWAP ((mp_ptr) data, zp, (mp_size_t) count);
Packit 5c3484
	      return data;
Packit 5c3484
	    }
Packit 5c3484
	  if (order == 1 && endian == -HOST_ENDIAN)
Packit 5c3484
	    {
Packit 5c3484
	      MPN_BSWAP_REVERSE ((mp_ptr) data, zp, (mp_size_t) count);
Packit 5c3484
	      return data;
Packit 5c3484
	    }
Packit 5c3484
	}
Packit 5c3484
    }
Packit 5c3484
Packit 5c3484
  {
Packit 5c3484
    mp_limb_t      limb, wbitsmask;
Packit 5c3484
    size_t         i, numb;
Packit 5c3484
    mp_size_t      j, wbytes, woffset;
Packit 5c3484
    unsigned char  *dp;
Packit 5c3484
    int            lbits, wbits;
Packit 5c3484
    mp_srcptr      zend;
Packit 5c3484
Packit 5c3484
    numb = size * 8 - nail;
Packit 5c3484
Packit 5c3484
    /* whole bytes per word */
Packit 5c3484
    wbytes = numb / 8;
Packit 5c3484
Packit 5c3484
    /* possible partial byte */
Packit 5c3484
    wbits = numb % 8;
Packit 5c3484
    wbitsmask = (CNST_LIMB(1) << wbits) - 1;
Packit 5c3484
Packit 5c3484
    /* offset to get to the next word */
Packit 5c3484
    woffset = (endian >= 0 ? size : - (mp_size_t) size)
Packit 5c3484
      + (order < 0 ? size : - (mp_size_t) size);
Packit 5c3484
Packit 5c3484
    /* least significant byte */
Packit 5c3484
    dp = (unsigned char *) data
Packit 5c3484
      + (order >= 0 ? (count-1)*size : 0) + (endian >= 0 ? size-1 : 0);
Packit 5c3484
Packit 5c3484
#define EXTRACT(N, MASK)                                \
Packit 5c3484
    do {                                                \
Packit 5c3484
      if (lbits >= (N))                                 \
Packit 5c3484
        {                                               \
Packit 5c3484
          *dp = limb MASK;                              \
Packit 5c3484
          limb >>= (N);                                 \
Packit 5c3484
          lbits -= (N);                                 \
Packit 5c3484
        }                                               \
Packit 5c3484
      else                                              \
Packit 5c3484
        {                                               \
Packit 5c3484
          mp_limb_t  newlimb;                           \
Packit 5c3484
          newlimb = (zp == zend ? 0 : *zp++);           \
Packit 5c3484
          *dp = (limb | (newlimb << lbits)) MASK;       \
Packit 5c3484
          limb = newlimb >> ((N)-lbits);                \
Packit 5c3484
          lbits += GMP_NUMB_BITS - (N);                 \
Packit 5c3484
        }                                               \
Packit 5c3484
    } while (0)
Packit 5c3484
Packit 5c3484
    zend = zp + zsize;
Packit 5c3484
    lbits = 0;
Packit 5c3484
    limb = 0;
Packit 5c3484
    for (i = 0; i < count; i++)
Packit 5c3484
      {
Packit 5c3484
	for (j = 0; j < wbytes; j++)
Packit 5c3484
	  {
Packit 5c3484
	    EXTRACT (8, + 0);
Packit 5c3484
	    dp -= endian;
Packit 5c3484
	  }
Packit 5c3484
	if (wbits != 0)
Packit 5c3484
	  {
Packit 5c3484
	    EXTRACT (wbits, & wbitsmask);
Packit 5c3484
	    dp -= endian;
Packit 5c3484
	    j++;
Packit 5c3484
	  }
Packit 5c3484
	for ( ; j < size; j++)
Packit 5c3484
	  {
Packit 5c3484
	    *dp = '\0';
Packit 5c3484
	    dp -= endian;
Packit 5c3484
	  }
Packit 5c3484
	dp += woffset;
Packit 5c3484
      }
Packit 5c3484
Packit 5c3484
    ASSERT (zp == PTR(z) + ABSIZ(z));
Packit 5c3484
Packit 5c3484
    /* low byte of word after most significant */
Packit 5c3484
    ASSERT (dp == (unsigned char *) data
Packit 5c3484
	    + (order < 0 ? count*size : - (mp_size_t) size)
Packit 5c3484
	    + (endian >= 0 ? (mp_size_t) size - 1 : 0));
Packit 5c3484
  }
Packit 5c3484
  return data;
Packit 5c3484
}