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