~drizzle-trunk/drizzle/development

1 by brian
clean slate
1
/**********************************************************************
2
Utilities for converting data from the database file
3
to the machine format.
4
5
(c) 1995 Innobase Oy
6
7
Created 11/28/1995 Heikki Tuuri
8
***********************************************************************/
9
10
#include "ut0mem.h"
11
12
/***********************************************************
13
The following function is used to store data in one byte. */
14
UNIV_INLINE
15
void
16
mach_write_to_1(
17
/*============*/
18
	byte*	b,	/* in: pointer to byte where to store */
19
	ulint	n)	/* in: ulint integer to be stored, >= 0, < 256 */
20
{
21
	ut_ad(b);
22
	ut_ad(n <= 0xFFUL);
23
24
	b[0] = (byte)n;
25
}
26
27
/************************************************************
28
The following function is used to fetch data from one byte. */
29
UNIV_INLINE
30
ulint
31
mach_read_from_1(
32
/*=============*/
33
			/* out: ulint integer, >= 0, < 256 */
34
	byte*	b)	/* in: pointer to byte */
35
{
36
	ut_ad(b);
37
	return((ulint)(b[0]));
38
}
39
40
/***********************************************************
41
The following function is used to store data in two consecutive
42
bytes. We store the most significant byte to the lowest address. */
43
UNIV_INLINE
44
void
45
mach_write_to_2(
46
/*============*/
47
	byte*	b,	/* in: pointer to two bytes where to store */
48
	ulint	n)	/* in: ulint integer to be stored */
49
{
50
	ut_ad(b);
51
	ut_ad(n <= 0xFFFFUL);
52
53
	b[0] = (byte)(n >> 8);
54
	b[1] = (byte)(n);
55
}
56
57
/************************************************************
58
The following function is used to fetch data from 2 consecutive
59
bytes. The most significant byte is at the lowest address. */
60
UNIV_INLINE
61
ulint
62
mach_read_from_2(
63
/*=============*/
64
			/* out: ulint integer */
65
	byte*	b)	/* in: pointer to 2 bytes */
66
{
67
	ut_ad(b);
68
	return( ((ulint)(b[0]) << 8)
69
		+ (ulint)(b[1])
70
		);
71
}
72
73
/************************************************************
74
The following function is used to convert a 16-bit data item
75
to the canonical format, for fast bytewise equality test
76
against memory. */
77
UNIV_INLINE
78
uint16
79
mach_encode_2(
80
/*==========*/
81
			/* out: 16-bit integer in canonical format */
82
	ulint	n)	/* in: integer in machine-dependent format */
83
{
84
	uint16	ret;
85
	ut_ad(2 == sizeof ret);
86
	mach_write_to_2((byte*) &ret, n);
87
	return(ret);
88
}
89
/************************************************************
90
The following function is used to convert a 16-bit data item
91
from the canonical format, for fast bytewise equality test
92
against memory. */
93
UNIV_INLINE
94
ulint
95
mach_decode_2(
96
/*==========*/
97
			/* out: integer in machine-dependent format */
98
	uint16	n)	/* in: 16-bit integer in canonical format */
99
{
100
	ut_ad(2 == sizeof n);
101
	return(mach_read_from_2((byte*) &n));
102
}
103
104
/***********************************************************
105
The following function is used to store data in 3 consecutive
106
bytes. We store the most significant byte to the lowest address. */
107
UNIV_INLINE
108
void
109
mach_write_to_3(
110
/*============*/
111
	byte*	b,	/* in: pointer to 3 bytes where to store */
112
	ulint	n)	/* in: ulint integer to be stored */
113
{
114
	ut_ad(b);
115
	ut_ad(n <= 0xFFFFFFUL);
116
117
	b[0] = (byte)(n >> 16);
118
	b[1] = (byte)(n >> 8);
119
	b[2] = (byte)(n);
120
}
121
122
/************************************************************
123
The following function is used to fetch data from 3 consecutive
124
bytes. The most significant byte is at the lowest address. */
125
UNIV_INLINE
126
ulint
127
mach_read_from_3(
128
/*=============*/
129
			/* out: ulint integer */
130
	byte*	b)	/* in: pointer to 3 bytes */
131
{
132
	ut_ad(b);
133
	return( ((ulint)(b[0]) << 16)
134
		+ ((ulint)(b[1]) << 8)
135
		+ (ulint)(b[2])
136
		);
137
}
138
139
/***********************************************************
140
The following function is used to store data in four consecutive
141
bytes. We store the most significant byte to the lowest address. */
142
UNIV_INLINE
143
void
144
mach_write_to_4(
145
/*============*/
146
	byte*	b,	/* in: pointer to four bytes where to store */
147
	ulint	n)	/* in: ulint integer to be stored */
148
{
149
	ut_ad(b);
150
151
	b[0] = (byte)(n >> 24);
152
	b[1] = (byte)(n >> 16);
153
	b[2] = (byte)(n >> 8);
154
	b[3] = (byte)n;
155
}
156
157
/************************************************************
158
The following function is used to fetch data from 4 consecutive
159
bytes. The most significant byte is at the lowest address. */
160
UNIV_INLINE
161
ulint
162
mach_read_from_4(
163
/*=============*/
164
			/* out: ulint integer */
165
	byte*	b)	/* in: pointer to four bytes */
166
{
167
	ut_ad(b);
168
	return( ((ulint)(b[0]) << 24)
169
		+ ((ulint)(b[1]) << 16)
170
		+ ((ulint)(b[2]) << 8)
171
		+ (ulint)(b[3])
172
		);
173
}
174
175
/*************************************************************
176
Writes a ulint in a compressed form where the first byte codes the
177
length of the stored ulint. We look at the most significant bits of
178
the byte. If the most significant bit is zero, it means 1-byte storage,
179
else if the 2nd bit is 0, it means 2-byte storage, else if 3rd is 0,
180
it means 3-byte storage, else if 4th is 0, it means 4-byte storage,
181
else the storage is 5-byte. */
182
UNIV_INLINE
183
ulint
184
mach_write_compressed(
185
/*==================*/
186
			/* out: compressed size in bytes */
187
	byte*	b,	/* in: pointer to memory where to store */
188
	ulint	n)	/* in: ulint integer (< 2^32) to be stored */
189
{
190
	ut_ad(b);
191
192
	if (n < 0x80UL) {
193
		mach_write_to_1(b, n);
194
		return(1);
195
	} else if (n < 0x4000UL) {
196
		mach_write_to_2(b, n | 0x8000UL);
197
		return(2);
198
	} else if (n < 0x200000UL) {
199
		mach_write_to_3(b, n | 0xC00000UL);
200
		return(3);
201
	} else if (n < 0x10000000UL) {
202
		mach_write_to_4(b, n | 0xE0000000UL);
203
		return(4);
204
	} else {
205
		mach_write_to_1(b, 0xF0UL);
206
		mach_write_to_4(b + 1, n);
207
		return(5);
208
	}
209
}
210
211
/*************************************************************
212
Returns the size of a ulint when written in the compressed form. */
213
UNIV_INLINE
214
ulint
215
mach_get_compressed_size(
216
/*=====================*/
217
			/* out: compressed size in bytes */
218
	ulint	n)	/* in: ulint integer (< 2^32) to be stored */
219
{
220
	if (n < 0x80UL) {
221
		return(1);
222
	} else if (n < 0x4000UL) {
223
		return(2);
224
	} else if (n < 0x200000UL) {
225
		return(3);
226
	} else if (n < 0x10000000UL) {
227
		return(4);
228
	} else {
229
		return(5);
230
	}
231
}
232
233
/*************************************************************
234
Reads a ulint in a compressed form. */
235
UNIV_INLINE
236
ulint
237
mach_read_compressed(
238
/*=================*/
239
			/* out: read integer (< 2^32) */
240
	byte*	b)	/* in: pointer to memory from where to read */
241
{
242
	ulint	flag;
243
244
	ut_ad(b);
245
246
	flag = mach_read_from_1(b);
247
248
	if (flag < 0x80UL) {
249
		return(flag);
250
	} else if (flag < 0xC0UL) {
251
		return(mach_read_from_2(b) & 0x7FFFUL);
252
	} else if (flag < 0xE0UL) {
253
		return(mach_read_from_3(b) & 0x3FFFFFUL);
254
	} else if (flag < 0xF0UL) {
255
		return(mach_read_from_4(b) & 0x1FFFFFFFUL);
256
	} else {
257
		ut_ad(flag == 0xF0UL);
258
		return(mach_read_from_4(b + 1));
259
	}
260
}
261
262
/***********************************************************
263
The following function is used to store data in 8 consecutive
264
bytes. We store the most significant byte to the lowest address. */
265
UNIV_INLINE
266
void
267
mach_write_to_8(
268
/*============*/
269
	byte*	b,	/* in: pointer to 8 bytes where to store */
270
	dulint	n)	/* in: dulint integer to be stored */
271
{
272
	ut_ad(b);
273
274
	mach_write_to_4(b, ut_dulint_get_high(n));
275
	mach_write_to_4(b + 4, ut_dulint_get_low(n));
276
}
277
278
/************************************************************
279
The following function is used to fetch data from 8 consecutive
280
bytes. The most significant byte is at the lowest address. */
281
UNIV_INLINE
282
dulint
283
mach_read_from_8(
284
/*=============*/
285
			/* out: dulint integer */
286
	byte*	b)	/* in: pointer to 8 bytes */
287
{
288
	ulint	high;
289
	ulint	low;
290
291
	ut_ad(b);
292
293
	high = mach_read_from_4(b);
294
	low = mach_read_from_4(b + 4);
295
296
	return(ut_dulint_create(high, low));
297
}
298
299
/***********************************************************
300
The following function is used to store data in 7 consecutive
301
bytes. We store the most significant byte to the lowest address. */
302
UNIV_INLINE
303
void
304
mach_write_to_7(
305
/*============*/
306
	byte*	b,	/* in: pointer to 7 bytes where to store */
307
	dulint	n)	/* in: dulint integer to be stored */
308
{
309
	ut_ad(b);
310
311
	mach_write_to_3(b, ut_dulint_get_high(n));
312
	mach_write_to_4(b + 3, ut_dulint_get_low(n));
313
}
314
315
/************************************************************
316
The following function is used to fetch data from 7 consecutive
317
bytes. The most significant byte is at the lowest address. */
318
UNIV_INLINE
319
dulint
320
mach_read_from_7(
321
/*=============*/
322
			/* out: dulint integer */
323
	byte*	b)	/* in: pointer to 7 bytes */
324
{
325
	ulint	high;
326
	ulint	low;
327
328
	ut_ad(b);
329
330
	high = mach_read_from_3(b);
331
	low = mach_read_from_4(b + 3);
332
333
	return(ut_dulint_create(high, low));
334
}
335
336
/***********************************************************
337
The following function is used to store data in 6 consecutive
338
bytes. We store the most significant byte to the lowest address. */
339
UNIV_INLINE
340
void
341
mach_write_to_6(
342
/*============*/
343
	byte*	b,	/* in: pointer to 6 bytes where to store */
344
	dulint	n)	/* in: dulint integer to be stored */
345
{
346
	ut_ad(b);
347
348
	mach_write_to_2(b, ut_dulint_get_high(n));
349
	mach_write_to_4(b + 2, ut_dulint_get_low(n));
350
}
351
352
/************************************************************
353
The following function is used to fetch data from 6 consecutive
354
bytes. The most significant byte is at the lowest address. */
355
UNIV_INLINE
356
dulint
357
mach_read_from_6(
358
/*=============*/
359
			/* out: dulint integer */
360
	byte*	b)	/* in: pointer to 7 bytes */
361
{
362
	ulint	high;
363
	ulint	low;
364
365
	ut_ad(b);
366
367
	high = mach_read_from_2(b);
368
	low = mach_read_from_4(b + 2);
369
370
	return(ut_dulint_create(high, low));
371
}
372
373
/*************************************************************
374
Writes a dulint in a compressed form (5..9 bytes). */
375
UNIV_INLINE
376
ulint
377
mach_dulint_write_compressed(
378
/*=========================*/
379
			/* out: size in bytes */
380
	byte*	b,	/* in: pointer to memory where to store */
381
	dulint	n)	/* in: dulint integer to be stored */
382
{
383
	ulint	size;
384
385
	ut_ad(b);
386
387
	size = mach_write_compressed(b, ut_dulint_get_high(n));
388
	mach_write_to_4(b + size, ut_dulint_get_low(n));
389
390
	return(size + 4);
391
}
392
393
/*************************************************************
394
Returns the size of a dulint when written in the compressed form. */
395
UNIV_INLINE
396
ulint
397
mach_dulint_get_compressed_size(
398
/*============================*/
399
			/* out: compressed size in bytes */
400
	dulint	 n)	/* in: dulint integer to be stored */
401
{
402
	return(4 + mach_get_compressed_size(ut_dulint_get_high(n)));
403
}
404
405
/*************************************************************
406
Reads a dulint in a compressed form. */
407
UNIV_INLINE
408
dulint
409
mach_dulint_read_compressed(
410
/*========================*/
411
			/* out: read dulint */
412
	byte*	b)	/* in: pointer to memory from where to read */
413
{
414
	ulint	high;
415
	ulint	low;
416
	ulint	size;
417
418
	ut_ad(b);
419
420
	high = mach_read_compressed(b);
421
422
	size = mach_get_compressed_size(high);
423
424
	low = mach_read_from_4(b + size);
425
426
	return(ut_dulint_create(high, low));
427
}
428
429
/*************************************************************
430
Writes a dulint in a compressed form (1..11 bytes). */
431
UNIV_INLINE
432
ulint
433
mach_dulint_write_much_compressed(
434
/*==============================*/
435
			/* out: size in bytes */
436
	byte*	b,	/* in: pointer to memory where to store */
437
	dulint	n)	/* in: dulint integer to be stored */
438
{
439
	ulint	size;
440
441
	ut_ad(b);
442
443
	if (ut_dulint_get_high(n) == 0) {
444
		return(mach_write_compressed(b, ut_dulint_get_low(n)));
445
	}
446
447
	*b = (byte)0xFF;
448
	size = 1 + mach_write_compressed(b + 1, ut_dulint_get_high(n));
449
450
	size += mach_write_compressed(b + size, ut_dulint_get_low(n));
451
452
	return(size);
453
}
454
455
/*************************************************************
456
Returns the size of a dulint when written in the compressed form. */
457
UNIV_INLINE
458
ulint
459
mach_dulint_get_much_compressed_size(
460
/*=================================*/
461
			/* out: compressed size in bytes */
462
	dulint	 n)	/* in: dulint integer to be stored */
463
{
464
	if (0 == ut_dulint_get_high(n)) {
465
		return(mach_get_compressed_size(ut_dulint_get_low(n)));
466
	}
467
468
	return(1 + mach_get_compressed_size(ut_dulint_get_high(n))
469
	       + mach_get_compressed_size(ut_dulint_get_low(n)));
470
}
471
472
/*************************************************************
473
Reads a dulint in a compressed form. */
474
UNIV_INLINE
475
dulint
476
mach_dulint_read_much_compressed(
477
/*=============================*/
478
			/* out: read dulint */
479
	byte*	b)	/* in: pointer to memory from where to read */
480
{
481
	ulint	high;
482
	ulint	low;
483
	ulint	size;
484
485
	ut_ad(b);
486
487
	if (*b != (byte)0xFF) {
488
		high = 0;
489
		size = 0;
490
	} else {
491
		high = mach_read_compressed(b + 1);
492
493
		size = 1 + mach_get_compressed_size(high);
494
	}
495
496
	low = mach_read_compressed(b + size);
497
498
	return(ut_dulint_create(high, low));
499
}
500
501
/*************************************************************
502
Reads a double. It is stored in a little-endian format. */
503
UNIV_INLINE
504
double
505
mach_double_read(
506
/*=============*/
507
			/* out: double read */
508
	byte*	b)	/* in: pointer to memory from where to read */
509
{
510
	double	d;
511
	ulint	i;
512
	byte*	ptr;
513
514
	ptr = (byte*)&d;
515
516
	for (i = 0; i < sizeof(double); i++) {
517
#ifdef WORDS_BIGENDIAN
518
		ptr[sizeof(double) - i - 1] = b[i];
519
#else
520
		ptr[i] = b[i];
521
#endif
522
	}
523
524
	return(d);
525
}
526
527
/*************************************************************
528
Writes a double. It is stored in a little-endian format. */
529
UNIV_INLINE
530
void
531
mach_double_write(
532
/*==============*/
533
	byte*	b,	/* in: pointer to memory where to write */
534
	double	d)	/* in: double */
535
{
536
	ulint	i;
537
	byte*	ptr;
538
539
	ptr = (byte*)&d;
540
541
	for (i = 0; i < sizeof(double); i++) {
542
#ifdef WORDS_BIGENDIAN
543
		b[i] = ptr[sizeof(double) - i - 1];
544
#else
545
		b[i] = ptr[i];
546
#endif
547
	}
548
}
549
550
/*************************************************************
551
Reads a float. It is stored in a little-endian format. */
552
UNIV_INLINE
553
float
554
mach_float_read(
555
/*============*/
556
			/* out: float read */
557
	byte*	b)	/* in: pointer to memory from where to read */
558
{
559
	float	d;
560
	ulint	i;
561
	byte*	ptr;
562
563
	ptr = (byte*)&d;
564
565
	for (i = 0; i < sizeof(float); i++) {
566
#ifdef WORDS_BIGENDIAN
567
		ptr[sizeof(float) - i - 1] = b[i];
568
#else
569
		ptr[i] = b[i];
570
#endif
571
	}
572
573
	return(d);
574
}
575
576
/*************************************************************
577
Writes a float. It is stored in a little-endian format. */
578
UNIV_INLINE
579
void
580
mach_float_write(
581
/*=============*/
582
	byte*	b,	/* in: pointer to memory where to write */
583
	float	d)	/* in: float */
584
{
585
	ulint	i;
586
	byte*	ptr;
587
588
	ptr = (byte*)&d;
589
590
	for (i = 0; i < sizeof(float); i++) {
591
#ifdef WORDS_BIGENDIAN
592
		b[i] = ptr[sizeof(float) - i - 1];
593
#else
594
		b[i] = ptr[i];
595
#endif
596
	}
597
}
598
599
/*************************************************************
600
Reads a ulint stored in the little-endian format. */
601
UNIV_INLINE
602
ulint
603
mach_read_from_n_little_endian(
604
/*===========================*/
605
				/* out: unsigned long int */
606
	byte*	buf,		/* in: from where to read */
607
	ulint	buf_size)	/* in: from how many bytes to read */
608
{
609
	ulint	n	= 0;
610
	byte*	ptr;
611
612
	ut_ad(buf_size <= sizeof(ulint));
613
	ut_ad(buf_size > 0);
614
615
	ptr = buf + buf_size;
616
617
	for (;;) {
618
		ptr--;
619
620
		n = n << 8;
621
622
		n += (ulint)(*ptr);
623
624
		if (ptr == buf) {
625
			break;
626
		}
627
	}
628
629
	return(n);
630
}
631
632
/*************************************************************
633
Writes a ulint in the little-endian format. */
634
UNIV_INLINE
635
void
636
mach_write_to_n_little_endian(
637
/*==========================*/
638
	byte*	dest,		/* in: where to write */
639
	ulint	dest_size,	/* in: into how many bytes to write */
640
	ulint	n)		/* in: unsigned long int to write */
641
{
642
	byte*	end;
643
644
	ut_ad(dest_size <= sizeof(ulint));
645
	ut_ad(dest_size > 0);
646
647
	end = dest + dest_size;
648
649
	for (;;) {
650
		*dest = (byte)(n & 0xFF);
651
652
		n = n >> 8;
653
654
		dest++;
655
656
		if (dest == end) {
657
			break;
658
		}
659
	}
660
661
	ut_ad(n == 0);
662
}
663
664
/*************************************************************
665
Reads a ulint stored in the little-endian format. */
666
UNIV_INLINE
667
ulint
668
mach_read_from_2_little_endian(
669
/*===========================*/
670
				/* out: unsigned long int */
671
	byte*	buf)		/* in: from where to read */
672
{
673
	return((ulint)(*buf) + ((ulint)(*(buf + 1))) * 256);
674
}
675
676
/*************************************************************
677
Writes a ulint in the little-endian format. */
678
UNIV_INLINE
679
void
680
mach_write_to_2_little_endian(
681
/*==========================*/
682
	byte*	dest,		/* in: where to write */
683
	ulint	n)		/* in: unsigned long int to write */
684
{
685
	ut_ad(n < 256 * 256);
686
687
	*dest = (byte)(n & 0xFFUL);
688
689
	n = n >> 8;
690
	dest++;
691
692
	*dest = (byte)(n & 0xFFUL);
693
}
694
695
/*************************************************************
696
Convert integral type from storage byte order (big endian) to
697
host byte order. */
698
UNIV_INLINE
699
void
700
mach_read_int_type(
701
/*===============*/
702
	byte*		dest,		/* out: where to write */
703
	const byte*	src,		/* in: where to read from */
704
	ulint		len,		/* in: length of src */
705
	ibool		unsigned_type)	/* in: signed or unsigned flag */
706
{
707
#ifdef WORDS_BIGENDIAN
708
	memcpy(dest, src, len);
709
710
	if (!unsigned_type) {
711
		dest[0] ^= 128;
712
	}
713
#else
714
	byte*		ptr;
715
716
	/* Convert integer data from Innobase to a little-endian format,
717
	sign bit restored to normal. */
718
719
	for (ptr = dest + len; ptr != dest; ++src) {
720
		--ptr;
721
		*ptr = *src;
722
	}
723
724
	if (!unsigned_type) {
725
		dest[len - 1] ^= 128;
726
	}
727
#endif
728
}