1 /* mpz_out_raw -- write an mpz_t in raw format. 2 3 Copyright 2001, 2002 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> 21 #include "gmp.h" 22 #include "gmp-impl.h" 23 #include "longlong.h" 24 25 26 /* HTON_LIMB_STORE takes a normal host byte order limb and stores it as 27 network byte order (ie. big endian). */ 28 29 #if HAVE_LIMB_BIG_ENDIAN 30 #define HTON_LIMB_STORE(dst, limb) do { *(dst) = (limb); } while (0) 31 #endif 32 33 #if HAVE_LIMB_LITTLE_ENDIAN 34 #define HTON_LIMB_STORE(dst, limb) BSWAP_LIMB_STORE (dst, limb) 35 #endif 36 37 #ifndef HTON_LIMB_STORE 38 #define HTON_LIMB_STORE(dst, limb) \ 39 do { \ 40 mp_limb_t __limb = (limb); \ 41 char *__p = (char *) (dst); \ 42 int __i; \ 43 for (__i = 0; __i < BYTES_PER_MP_LIMB; __i++) \ 44 __p[__i] = (char) (__limb >> ((BYTES_PER_MP_LIMB-1 - __i) * 8)); \ 45 } while (0) 46 #endif 47 48 49 size_t 50 mpz_out_raw (FILE *fp, mpz_srcptr x) 51 { 52 mp_size_t xsize, abs_xsize, bytes, i; 53 mp_srcptr xp; 54 char *tp, *bp; 55 mp_limb_t xlimb; 56 int zeros; 57 size_t tsize, ssize; 58 59 xsize = SIZ(x); 60 abs_xsize = ABS (xsize); 61 bytes = (abs_xsize * GMP_NUMB_BITS + 7) / 8; 62 tsize = ROUND_UP_MULTIPLE ((unsigned) 4, BYTES_PER_MP_LIMB) + bytes; 63 64 tp = __GMP_ALLOCATE_FUNC_TYPE (tsize, char); 65 bp = tp + ROUND_UP_MULTIPLE ((unsigned) 4, BYTES_PER_MP_LIMB); 66 67 if (bytes != 0) 68 { 69 bp += bytes; 70 xp = PTR (x); 71 i = abs_xsize; 72 73 if (GMP_NAIL_BITS == 0) 74 { 75 /* reverse limb order, and byte swap if necessary */ 76 #ifdef _CRAY 77 _Pragma ("_CRI ivdep"); 78 #endif 79 do 80 { 81 bp -= BYTES_PER_MP_LIMB; 82 xlimb = *xp; 83 HTON_LIMB_STORE ((mp_ptr) bp, xlimb); 84 xp++; 85 } 86 while (--i > 0); 87 88 /* strip high zero bytes (without fetching from bp) */ 89 count_leading_zeros (zeros, xlimb); 90 zeros /= 8; 91 bp += zeros; 92 bytes -= zeros; 93 } 94 else 95 { 96 mp_limb_t new_xlimb; 97 int bits; 98 ASSERT_CODE (char *bp_orig = bp - bytes); 99 100 ASSERT_ALWAYS (GMP_NUMB_BITS >= 8); 101 102 bits = 0; 103 xlimb = 0; 104 for (;;) 105 { 106 while (bits >= 8) 107 { 108 ASSERT (bp > bp_orig); 109 *--bp = xlimb & 0xFF; 110 xlimb >>= 8; 111 bits -= 8; 112 } 113 114 if (i == 0) 115 break; 116 117 new_xlimb = *xp++; 118 i--; 119 ASSERT (bp > bp_orig); 120 *--bp = (xlimb | (new_xlimb << bits)) & 0xFF; 121 xlimb = new_xlimb >> (8 - bits); 122 bits += GMP_NUMB_BITS - 8; 123 } 124 125 if (bits != 0) 126 { 127 ASSERT (bp > bp_orig); 128 *--bp = xlimb; 129 } 130 131 ASSERT (bp == bp_orig); 132 while (*bp == 0) 133 { 134 bp++; 135 bytes--; 136 } 137 } 138 } 139 140 /* total bytes to be written */ 141 ssize = 4 + bytes; 142 143 /* twos complement negative for the size value */ 144 bytes = (xsize >= 0 ? bytes : -bytes); 145 146 /* so we don't rely on sign extension in ">>" */ 147 ASSERT_ALWAYS (sizeof (bytes) >= 4); 148 149 bp[-4] = bytes >> 24; 150 bp[-3] = bytes >> 16; 151 bp[-2] = bytes >> 8; 152 bp[-1] = bytes; 153 bp -= 4; 154 155 if (fp == 0) 156 fp = stdout; 157 if (fwrite (bp, ssize, 1, fp) != 1) 158 ssize = 0; 159 160 (*__gmp_free_func) (tp, tsize); 161 return ssize; 162 } 163