1 /* Serialization of integers into a little-endian sequence of bytes
2 
3  Converts a little-endian byte sequence to an unsigned integer.
4  > bytesize: number of given 8-bit bytes of the integer,
5              < intDsize/8*uintWC_max
6  > bufferptr: address of bytesize bytes in GC-invariant memory
7  < result: an integer >= 0 with I_integer_length(result) <= 8*bytesize
8  can trigger GC */
LEbytes_to_UI(uintL bytesize,const uintB * bufferptr)9 modexp maygc object LEbytes_to_UI (uintL bytesize, const uintB* bufferptr) {
10   var gcv_object_t fake; fake = FAKE_8BIT_VECTOR(bufferptr);
11   return LESbvector_to_UI(bytesize,&fake);
12 }
13 
14 /* Converts a little-endian byte sequence to an unsigned integer.
15  > bytesize: number of given 8-bit bytes of the integer,
16              < intDsize/8*uintWC_max
17  > *buffer_: address of a simple-8bit-vector (or of a fake)
18              containing bytesize bytes of memory
19  < result: an integer >= 0 with I_integer_length(result) <= 8*bytesize
20  can trigger GC */
LESbvector_to_UI(uintL bytesize,const gcv_object_t * buffer_)21 global maygc object LESbvector_to_UI (uintL bytesize, const gcv_object_t* buffer_) {
22   /* Normalize number in buffer: */
23   var uintB* bufferptr = &TheSbvector(*buffer_)->data[bytesize-1];
24   var uintL count = bytesize;
25   while ((!(count==0)) && (*bufferptr==0)) { count--; bufferptr--; }
26   /* Make number: */
27   if                            /* at most oint_data_len Bits ? */
28     ((count <= floor(oint_data_len,8))
29      || ((count == floor(oint_data_len,8)+1)
30          && (*bufferptr < bit(oint_data_len%8)))) {
31     /* yes -> build Fixnum >=0 : */
32     var uintV value = 0;
33     while (count != 0) { value = (value<<8) | *bufferptr--; count--; }
34     return fixnum(value);
35   }
36   /* no -> build Bignum >0 : */
37   var uintL digitcount = floor(count,(intDsize/8));
38   if (((count%(intDsize/8)) > 0) || (*bufferptr & bit(7)))
39     digitcount++;
40   /* As bitsize < intDsize*uintWC_max,
41    digitcount <= ceiling((bitsize+1)/intDsize) <= uintWC_max . */
42   var object big = allocate_bignum(digitcount,0); /* new Bignum >0 */
43   TheBignum(big)->data[0] = 0;  /* set highest Digit to 0 */
44   /* Fill remaining Digits from right to left,
45    thereby translate sequence of Bytes into sequence of uintD: */
46   bufferptr = &TheSbvector(*buffer_)->data[0];
47   #if BIG_ENDIAN_P
48   {
49     var uintB* bigptr = (uintB*)(&TheBignum(big)->data[digitcount]);
50     dotimespL(count,count, { *--bigptr = *bufferptr++; } );
51   }
52   #else
53   {
54     var uintD* bigptr = &TheBignum(big)->data[digitcount];
55     var uintL count2;
56     #define GET_NEXT_BYTE(i)  digit |= ((uintD)(*bufferptr++) << (8*i));
57     dotimespL(count2,floor(count,intDsize/8), {
58       var uintD digit = 0;
59       DOCONSTTIMES(intDsize/8,GET_NEXT_BYTE); /* GET_NEXT_BYTE(0..intDsize/8-1) */
60       *--bigptr = digit;
61     });
62     #undef GET_NEXT_BYTE
63     count2 = count % (intDsize/8);
64     if (count2>0) {
65       var uintL shiftcount = 0;
66       var uintD digit = (uintD)(*bufferptr++);
67       dotimesL(count2,count2-1, {
68         shiftcount += 8;
69         digit |= ((uintD)(*bufferptr++) << shiftcount);
70       });
71       *--bigptr = digit;
72     }
73   }
74   #endif
75   /* Since (intDsize/8)*(digitcount-1) <= count <= (intDsize/8)*digitcount
76    everything is filled. */
77   return big;
78 }
79 
80 /* Converts a little-endian byte sequence to an integer.
81  > bytesize: number of given 8-bit bytes of the integer, > 0,
82              < intDsize/8*uintWC_max
83  > bufferptr: address of bytesize bytes in GC-invariant memory
84  < result: an integer with I_integer_length(result) < 8*bytesize
85  can trigger GC */
LEbytes_to_I(uintL bytesize,const uintB * bufferptr)86 modexp maygc object LEbytes_to_I (uintL bytesize, const uintB* bufferptr) {
87   var gcv_object_t fake; fake = FAKE_8BIT_VECTOR(bufferptr);
88   return LESbvector_to_I(bytesize,&fake);
89 }
90 
91 /* Converts a little-endian byte sequence to an integer.
92  > bytesize: number of given 8-bit bytes of the integer, > 0,
93              < intDsize/8*uintWC_max
94  > *buffer_: address of a simple-8bit-vector (or of a fake)
95              containing bytesize bytes of memory
96  < result: an integer with I_integer_length(result) < 8*bytesize
97  can trigger GC */
LESbvector_to_I(uintL bytesize,const gcv_object_t * buffer_)98 global maygc object LESbvector_to_I (uintL bytesize, const gcv_object_t* buffer_) {
99   /* Normalize number in buffer: */
100   var uintB* bufferptr = &TheSbvector(*buffer_)->data[bytesize-1];
101   var sintD sign;
102   var uintL count = bytesize;
103   if (!(*bufferptr & bit(7))) {
104     sign = 0;
105     /* Normalize, highest Bit must remain 0: */
106     while ((count>=2) && (*bufferptr==0)
107            && !(*(bufferptr-1) & bit(7))) {
108       count--; bufferptr--;
109     }
110     /* Make number: */
111     if      /* at most oint_data_len+1 Bits, count <2^oint_data_len ? */
112       ((count <= floor(oint_data_len,8))
113        || ((count == floor(oint_data_len,8)+1)
114            && (*bufferptr < bit(oint_data_len%8)))) {
115       /* yes -> build Fixnum >=0: */
116       var uintV value = 0;
117       while (count != 0) { value = (value<<8) | *bufferptr--; count--; }
118       return posfixnum(value);
119     }
120   } else {
121     sign = -1;
122     /* Normalize, highest Bit must remain 1: */
123     while ((count>=2) && (*bufferptr==(uintB)(-1))
124            && (*(bufferptr-1) & bit(7))) {
125       count--; bufferptr--;
126     }
127     /* Make number: */
128     if    /* at most oint_data_len+1 Bits, count >=-2^oint_data_len ? */
129       ((count <= floor(oint_data_len,8))
130        || ((count == floor(oint_data_len,8)+1)
131            && (*bufferptr >= (uintB)(-bit(oint_data_len%8))))) {
132       /* yes -> build Fixnum <0: */
133       var uintV value = (uintV)(sintV)(-1);
134       while (count != 0) { value = (value<<8) | *bufferptr--; count--; }
135       return negfixnum(-wbitm(intVsize)+(oint)value);
136     }
137   }
138   /* Make bignum: */
139   var uintL digitcount = ceiling(count,(intDsize/8));
140   /* As bitsize < intDsize*uintWC_max,
141    digitcount <= ceiling(bitsize/intDsize) <= uintWC_max . */
142   var object big = allocate_bignum(digitcount,(sintB)sign);
143   TheBignum(big)->data[0] = sign; /* set highest Word to sign */
144   /* Fill the remaining Digits from right to left,
145    thereby translate sequence of Bytes into sequence of uintD: */
146   bufferptr = &TheSbvector(*buffer_)->data[0];
147   #if BIG_ENDIAN_P
148   {
149     var uintB* bigptr = (uintB*)(TheBignum(big)->data+digitcount);
150     dotimespL(count,count, { *--bigptr = *bufferptr++; } );
151   }
152   #else
153   {
154     var uintD* bigptr = TheBignum(big)->data+digitcount;
155     var uintL count2;
156     #define GET_NEXT_BYTE(i)  digit |= ((uintD)(*bufferptr++) << (8*i));
157     dotimespL(count2,floor(count,intDsize/8), {
158       var uintD digit = 0;
159       DOCONSTTIMES(intDsize/8,GET_NEXT_BYTE); /* GET_NEXT_BYTE(0..intDsize/8-1) */
160       *--bigptr = digit;
161     });
162     #undef GET_NEXT_BYTE
163     count2 = count % (intDsize/8);
164     if (count2>0) {
165       var uintL shiftcount = 0;
166       var uintD digit = (uintD)(*bufferptr++);
167       dotimesL(count2,count2-1, {
168         shiftcount += 8;
169         digit |= ((uintD)(*bufferptr++) << shiftcount);
170       });
171       *--bigptr = digit ^ (sign << (shiftcount+8));
172     }
173   }
174   #endif
175   /* Since (intDsize/8)*(digitcount-1) < count <= (intDsize/8)*digitcount
176    everything is filled. */
177   return big;
178 }
179 
180 /* Converts an unsigned integer to a little-endian byte sequence.
181  > obj: an integer
182  > bitsize: maximum number of bits of the integer
183  > bufferptr: pointer to bytesize = ceiling(bitsize,8) bytes of memory
184  < false and bufferptr[0..bytesize-1] filled, if obj >= 0 and
185                                               I_integer_length(obj) <= bitsize;
186    true, if obj is out of range */
UI_to_LEbytes(object obj,uintL bitsize,uintB * bufferptr)187 modexp bool UI_to_LEbytes (object obj, uintL bitsize, uintB* bufferptr) {
188   if (!positivep(obj))
189     return true;
190   /* obj is an integer >=0. */
191   var uintL bytesize = ceiling(bitsize,8);
192   /* Transfer obj into the buffer: */
193   {
194     var uintL count = bytesize;
195     if (posfixnump(obj)) {      /* obj is a Fixnum >=0 */
196       var uintV value = posfixnum_to_V(obj);
197       /* check value < 2^bitsize: */
198       if (!((bitsize>=oint_data_len) || (value < vbit(bitsize))))
199         return true;
200       /* store value in Bitbuffer: */
201       while (value != 0) {
202         *bufferptr++ = (uint8)value; value = value>>8; count--;
203       }
204     } else {                    /* obj is a Bignum >0 */
205       var uintL len = (uintL)Bignum_length(obj);
206       /* check obj < 2^bitsize: */
207       if (!((floor(bitsize,intDsize) >= len)
208             || ((floor(bitsize,intDsize) == len-1)
209                 && (TheBignum(obj)->data[0] < bit(bitsize%intDsize)))))
210         return true;
211       #if BIG_ENDIAN_P
212       {
213         var uintB* ptr = (uintB*)&TheBignum(obj)->data[len];
214         /* convert Digit-Length in Byte-Length: */
215         len = (intDsize/8)*len;
216         #define CHECK_NEXT_BYTE(i)  \
217           if (((uintB*)(&TheBignum(obj)->data[0]))[i] != 0) goto len_ok; \
218           len--;
219         DOCONSTTIMES(intDsize/8,CHECK_NEXT_BYTE); /* CHECK_NEXT_BYTE(0..intDsize/8-1) */
220         #undef CHECK_NEXT_BYTE
221       len_ok:
222         /* store obj in Bitbuffer: */
223         count = count - len;
224         dotimespL(len,len, { *bufferptr++ = *--ptr; } );
225       }
226       #else
227       {
228         var uintD* ptr = &TheBignum(obj)->data[len];
229         len--;
230         count -= (intDsize/8)*len;
231         dotimesL(len,len, {
232           var uintD digit = *--ptr;
233           doconsttimes(intDsize/8, {
234             *bufferptr++ = (uintB)digit; digit = digit >> 8;
235           });
236         });
237         var uintD digit = *--ptr;
238         doconsttimes(intDsize/8, {
239           if (digit==0) goto ok;
240           *bufferptr++ = (uintB)digit; digit = digit >> 8;
241           count--;
242         });
243       ok: ;
244       }
245     #endif
246     }
247     if (count > 0) {
248       begin_system_call();
249       memset(bufferptr,0,count);
250       end_system_call();
251     }
252   }
253   return false;
254 }
255 
256 /* Converts an integer to a little-endian byte sequence.
257  > obj: an integer
258  > bitsize: maximum number of bits of the integer, including the sign bit
259  > bufferptr: pointer to bytesize = ceiling(bitsize,8) bytes of memory
260  < false and bufferptr[0..bytesize-1] filled, if I_integer_length(obj) < bitsize;
261    true, if obj is out of range */
I_to_LEbytes(object obj,uintL bitsize,uintB * bufferptr)262 modexp bool I_to_LEbytes (object obj, uintL bitsize, uintB* bufferptr) {
263   /* obj is an integer. */
264   var uintL bytesize = ceiling(bitsize,8);
265   /* Transfer obj into the buffer: */
266   {
267     var uintL count = bytesize;
268     var uintV sign = (sintV)(sintL)R_sign(obj);
269     if (fixnump(obj)) { /* obj is a Fixnum */
270       var uintV value = fixnum_to_V(obj); /* >=0 or <0, according to sign */
271       /* check 0 <= value < 2^(bitsize-1) resp. -2^(bitsize-1) <= value < 0: */
272       value = value^sign;
273       if (!((bitsize>oint_data_len) || (value < bit(bitsize-1))))
274         return true;
275       /* store value^sign in Bitbuffer: */
276       while (value != 0) {
277         *bufferptr++ = (uint8)(value^sign); value = value>>8; count--;
278       }
279       if (count > 0) {
280         begin_system_call();
281         memset(bufferptr,(uint8)sign,count);
282         end_system_call();
283       }
284     } else { /* obj is a Bignum */
285       var uintL len = (uintL)Bignum_length(obj);
286       /* check -2^(bitsize-1) <= obj < 2^(bitsize-1): */
287       if (!((floor(bitsize,intDsize) >= len)
288             || ((bitsize > intDsize*(len-1))
289                 && ((TheBignum(obj)->data[0] ^ (uintD)sign) <
290                     bit((bitsize%intDsize)-1)))))
291         return true;
292       #if BIG_ENDIAN_P
293       {
294         var uintB* ptr = (uintB*)&TheBignum(obj)->data[len];
295         /* convert Digit-Length in Byte-Length: */
296         len = (intDsize/8)*len;
297         #define CHECK_NEXT_BYTE(i)  \
298           if (((uintB*)(&TheBignum(obj)->data[0]))[i] != (uintB)sign) goto len_ok; \
299           len--;
300         DOCONSTTIMES(intDsize/8,CHECK_NEXT_BYTE); /* CHECK_NEXT_BYTE(0..intDsize/8-1) */
301         #undef CHECK_NEXT_BYTE
302       len_ok:
303         /* store obj in Bitbuffer: */
304         count = count - len;
305         dotimespL(len,len, { *bufferptr++ = *--ptr; } );
306       }
307       #else
308       {
309         var uintD* ptr = &TheBignum(obj)->data[len];
310         len--;
311         count -= (intDsize/8)*len;
312         dotimesL(len,len, {
313           var uintD digit = *--ptr;
314           doconsttimes(intDsize/8, {
315             *bufferptr++ = (uintB)digit; digit = digit >> 8;
316           });
317         });
318         var sintD digit = *--ptr;
319         doconsttimes(intDsize/8, {
320           if (digit == (sintD)sign) goto ok;
321           *bufferptr++ = (uintB)digit; digit = digit >> 8;
322           count--;
323         });
324       ok: ;
325       }
326       #endif
327       if (count > 0) {
328         begin_system_call();
329         memset(bufferptr,(uintB)sign,count);
330         end_system_call();
331       }
332     }
333   }
334   return false;
335 }
336