1 /* mpz_export -- create word data from mpz. 2 3 Copyright 2002, 2003, 2012 Free Software Foundation, Inc. 4 5 This file is part of the GNU MP Library. 6 7 The GNU MP Library is free software; you can redistribute it and/or modify 8 it under the terms of the GNU Lesser General Public License as published by 9 the Free Software Foundation; either version 3 of the License, or (at your 10 option) any later version. 11 12 The GNU MP Library is distributed in the hope that it will be useful, but 13 WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 14 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 15 License for more details. 16 17 You should have received a copy of the GNU Lesser General Public License 18 along with the GNU MP Library. If not, see http://www.gnu.org/licenses/. */ 19 20 #include <stdio.h> /* for NULL */ 21 #include "gmp.h" 22 #include "gmp-impl.h" 23 #include "longlong.h" 24 25 26 #if HAVE_LIMB_BIG_ENDIAN 27 #define HOST_ENDIAN 1 28 #endif 29 #if HAVE_LIMB_LITTLE_ENDIAN 30 #define HOST_ENDIAN (-1) 31 #endif 32 #ifndef HOST_ENDIAN 33 static const mp_limb_t endian_test = (CNST_LIMB(1) << (GMP_LIMB_BITS-7)) - 1; 34 #define HOST_ENDIAN (* (signed char *) &endian_test) 35 #endif 36 37 void * 38 mpz_export (void *data, size_t *countp, int order, 39 size_t size, int endian, size_t nail, mpz_srcptr z) 40 { 41 mp_size_t zsize; 42 mp_srcptr zp; 43 size_t count, dummy; 44 unsigned long numb; 45 unsigned align; 46 47 ASSERT (order == 1 || order == -1); 48 ASSERT (endian == 1 || endian == 0 || endian == -1); 49 ASSERT (nail <= 8*size); 50 ASSERT (nail < 8*size || SIZ(z) == 0); /* nail < 8*size+(SIZ(z)==0) */ 51 52 if (countp == NULL) 53 countp = &dummy; 54 55 zsize = SIZ(z); 56 if (zsize == 0) 57 { 58 *countp = 0; 59 return data; 60 } 61 62 zsize = ABS (zsize); 63 zp = PTR(z); 64 numb = 8*size - nail; 65 MPN_SIZEINBASE_2EXP (count, zp, zsize, numb); 66 *countp = count; 67 68 if (data == NULL) 69 data = (*__gmp_allocate_func) (count*size); 70 71 if (endian == 0) 72 endian = HOST_ENDIAN; 73 74 align = ((char *) data - (char *) NULL) % sizeof (mp_limb_t); 75 76 if (nail == GMP_NAIL_BITS) 77 { 78 if (size == sizeof (mp_limb_t) && align == 0) 79 { 80 if (order == -1 && endian == HOST_ENDIAN) 81 { 82 MPN_COPY ((mp_ptr) data, zp, (mp_size_t) count); 83 return data; 84 } 85 if (order == 1 && endian == HOST_ENDIAN) 86 { 87 MPN_REVERSE ((mp_ptr) data, zp, (mp_size_t) count); 88 return data; 89 } 90 91 if (order == -1 && endian == -HOST_ENDIAN) 92 { 93 MPN_BSWAP ((mp_ptr) data, zp, (mp_size_t) count); 94 return data; 95 } 96 if (order == 1 && endian == -HOST_ENDIAN) 97 { 98 MPN_BSWAP_REVERSE ((mp_ptr) data, zp, (mp_size_t) count); 99 return data; 100 } 101 } 102 } 103 104 { 105 mp_limb_t limb, wbitsmask; 106 size_t i, numb; 107 mp_size_t j, wbytes, woffset; 108 unsigned char *dp; 109 int lbits, wbits; 110 mp_srcptr zend; 111 112 numb = size * 8 - nail; 113 114 /* whole bytes per word */ 115 wbytes = numb / 8; 116 117 /* possible partial byte */ 118 wbits = numb % 8; 119 wbitsmask = (CNST_LIMB(1) << wbits) - 1; 120 121 /* offset to get to the next word */ 122 woffset = (endian >= 0 ? size : - (mp_size_t) size) 123 + (order < 0 ? size : - (mp_size_t) size); 124 125 /* least significant byte */ 126 dp = (unsigned char *) data 127 + (order >= 0 ? (count-1)*size : 0) + (endian >= 0 ? size-1 : 0); 128 129 #define EXTRACT(N, MASK) \ 130 do { \ 131 if (lbits >= (N)) \ 132 { \ 133 *dp = limb MASK; \ 134 limb >>= (N); \ 135 lbits -= (N); \ 136 } \ 137 else \ 138 { \ 139 mp_limb_t newlimb; \ 140 newlimb = (zp == zend ? 0 : *zp++); \ 141 *dp = (limb | (newlimb << lbits)) MASK; \ 142 limb = newlimb >> ((N)-lbits); \ 143 lbits += GMP_NUMB_BITS - (N); \ 144 } \ 145 } while (0) 146 147 zend = zp + zsize; 148 lbits = 0; 149 limb = 0; 150 for (i = 0; i < count; i++) 151 { 152 for (j = 0; j < wbytes; j++) 153 { 154 EXTRACT (8, + 0); 155 dp -= endian; 156 } 157 if (wbits != 0) 158 { 159 EXTRACT (wbits, & wbitsmask); 160 dp -= endian; 161 j++; 162 } 163 for ( ; j < size; j++) 164 { 165 *dp = '\0'; 166 dp -= endian; 167 } 168 dp += woffset; 169 } 170 171 ASSERT (zp == PTR(z) + ABSIZ(z)); 172 173 /* low byte of word after most significant */ 174 ASSERT (dp == (unsigned char *) data 175 + (order < 0 ? count*size : - (mp_size_t) size) 176 + (endian >= 0 ? (mp_size_t) size - 1 : 0)); 177 } 178 return data; 179 } 180