1/*****************************************************************************
2
3Copyright (c) 1995, 2015, Oracle and/or its affiliates. All Rights Reserved.
4Copyright (c) 2017, 2020, MariaDB Corporation.
5
6This program is free software; you can redistribute it and/or modify it under
7the terms of the GNU General Public License as published by the Free Software
8Foundation; version 2 of the License.
9
10This program is distributed in the hope that it will be useful, but WITHOUT
11ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
12FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
13
14You should have received a copy of the GNU General Public License along with
15this program; if not, write to the Free Software Foundation, Inc.,
1651 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA
17
18*****************************************************************************/
19
20/******************************************************************//**
21@file include/mach0data.ic
22Utilities for converting data from the database file
23to the machine format.
24
25Created 11/28/1995 Heikki Tuuri
26***********************************************************************/
27
28#ifndef UNIV_INNOCHECKSUM
29
30#include "mtr0types.h"
31
32/*******************************************************//**
33The following function is used to store data in one byte. */
34UNIV_INLINE
35void
36mach_write_to_1(
37/*============*/
38	byte*	b,	/*!< in: pointer to byte where to store */
39	ulint	n)	/*!< in: ulint integer to be stored, >= 0, < 256 */
40{
41	ut_ad((n & ~0xFFUL) == 0);
42
43	b[0] = (byte) n;
44}
45
46#endif /* !UNIV_INNOCHECKSUM */
47
48/*******************************************************//**
49The following function is used to store data in two consecutive
50bytes. We store the most significant byte to the lowest address. */
51UNIV_INLINE
52void
53mach_write_to_2(
54/*============*/
55	byte*	b,	/*!< in: pointer to two bytes where to store */
56	ulint	n)	/*!< in: ulint integer to be stored */
57{
58	ut_ad((n & ~0xFFFFUL) == 0);
59
60	b[0] = (byte)(n >> 8);
61	b[1] = (byte)(n);
62}
63
64/** The following function is used to fetch data from one byte.
65@param[in]	b	pointer to a byte to read
66@return ulint integer, >= 0, < 256 */
67UNIV_INLINE
68uint8_t
69mach_read_from_1(
70	const byte*	b)
71{
72	return(uint8_t(*b));
73}
74
75/** The following function is used to fetch data from 2 consecutive
76bytes. The most significant byte is at the lowest address.
77@param[in]	b	pointer to 2 bytes to read
78@return 2-byte integer, >= 0, < 64k */
79UNIV_INLINE
80uint16_t
81mach_read_from_2(
82	const byte*	b)
83{
84	return(uint16_t(uint16_t(b[0]) << 8 | b[1]));
85}
86
87#ifndef UNIV_INNOCHECKSUM
88
89/********************************************************//**
90The following function is used to convert a 16-bit data item
91to the canonical format, for fast bytewise equality test
92against memory.
93@return 16-bit integer in canonical format */
94UNIV_INLINE
95uint16
96mach_encode_2(
97/*==========*/
98	ulint	n)	/*!< in: integer in machine-dependent format */
99{
100	uint16	ret;
101	ut_ad(2 == sizeof ret);
102	mach_write_to_2((byte*) &ret, n);
103	return(ret);
104}
105/********************************************************//**
106The following function is used to convert a 16-bit data item
107from the canonical format, for fast bytewise equality test
108against memory.
109@return integer in machine-dependent format */
110UNIV_INLINE
111ulint
112mach_decode_2(
113/*==========*/
114	uint16	n)	/*!< in: 16-bit integer in canonical format */
115{
116	ut_ad(2 == sizeof n);
117	return(mach_read_from_2((const byte*) &n));
118}
119
120/*******************************************************//**
121The following function is used to store data in 3 consecutive
122bytes. We store the most significant byte to the lowest address. */
123UNIV_INLINE
124void
125mach_write_to_3(
126/*============*/
127	byte*	b,	/*!< in: pointer to 3 bytes where to store */
128	ulint	n)	/*!< in: ulint integer to be stored */
129{
130	ut_ad((n & ~0xFFFFFFUL) == 0);
131
132	b[0] = (byte)(n >> 16);
133	b[1] = (byte)(n >> 8);
134	b[2] = (byte)(n);
135}
136
137/** The following function is used to fetch data from 3 consecutive
138bytes. The most significant byte is at the lowest address.
139@param[in]	b	pointer to 3 bytes to read
140@return uint32_t integer */
141UNIV_INLINE
142uint32_t
143mach_read_from_3(
144	const byte*	b)
145{
146	return( (static_cast<uint32_t>(b[0]) << 16)
147		| (static_cast<uint32_t>(b[1]) << 8)
148		| static_cast<uint32_t>(b[2])
149		);
150}
151#endif /* !UNIV_INNOCHECKSUM */
152
153/*******************************************************//**
154The following function is used to store data in four consecutive
155bytes. We store the most significant byte to the lowest address. */
156UNIV_INLINE
157void
158mach_write_to_4(
159/*============*/
160	byte*	b,	/*!< in: pointer to four bytes where to store */
161	ulint	n)	/*!< in: ulint integer to be stored */
162{
163	b[0] = (byte)(n >> 24);
164	b[1] = (byte)(n >> 16);
165	b[2] = (byte)(n >> 8);
166	b[3] = (byte) n;
167}
168
169/** The following function is used to fetch data from 4 consecutive
170bytes. The most significant byte is at the lowest address.
171@param[in]	b	pointer to 4 bytes to read
172@return 32 bit integer */
173UNIV_INLINE
174uint32_t
175mach_read_from_4(
176	const byte*	b)
177{
178	return( (static_cast<uint32_t>(b[0]) << 24)
179		| (static_cast<uint32_t>(b[1]) << 16)
180		| (static_cast<uint32_t>(b[2]) << 8)
181		| static_cast<uint32_t>(b[3])
182		);
183}
184
185#ifndef UNIV_INNOCHECKSUM
186
187/*********************************************************//**
188Writes a ulint in a compressed form where the first byte codes the
189length of the stored ulint. We look at the most significant bits of
190the byte. If the most significant bit is zero, it means 1-byte storage,
191else if the 2nd bit is 0, it means 2-byte storage, else if 3rd is 0,
192it means 3-byte storage, else if 4th is 0, it means 4-byte storage,
193else the storage is 5-byte.
194@return compressed size in bytes */
195UNIV_INLINE
196ulint
197mach_write_compressed(
198/*==================*/
199	byte*	b,	/*!< in: pointer to memory where to store */
200	ulint	n)	/*!< in: ulint integer (< 2^32) to be stored */
201{
202	if (n < 0x80) {
203		/* 0nnnnnnn (7 bits) */
204		mach_write_to_1(b, n);
205		return(1);
206	} else if (n < 0x4000) {
207		/* 10nnnnnn nnnnnnnn (14 bits) */
208		mach_write_to_2(b, n | 0x8000);
209		return(2);
210	} else if (n < 0x200000) {
211		/* 110nnnnn nnnnnnnn nnnnnnnn (21 bits) */
212		mach_write_to_3(b, n | 0xC00000);
213		return(3);
214	} else if (n < 0x10000000) {
215		/* 1110nnnn nnnnnnnn nnnnnnnn nnnnnnnn (28 bits) */
216		mach_write_to_4(b, n | 0xE0000000);
217		return(4);
218	} else {
219		/* 11110000 nnnnnnnn nnnnnnnn nnnnnnnn nnnnnnnn (32 bits) */
220		mach_write_to_1(b, 0xF0);
221		mach_write_to_4(b + 1, n);
222		return(5);
223	}
224}
225
226/*********************************************************//**
227Returns the size of a ulint when written in the compressed form.
228@return compressed size in bytes */
229UNIV_INLINE
230ulint
231mach_get_compressed_size(
232/*=====================*/
233	ulint	n)	/*!< in: ulint integer (< 2^32) to be stored */
234{
235	if (n < 0x80) {
236		/* 0nnnnnnn (7 bits) */
237		return(1);
238	} else if (n < 0x4000) {
239		/* 10nnnnnn nnnnnnnn (14 bits) */
240		return(2);
241	} else if (n < 0x200000) {
242		/* 110nnnnn nnnnnnnn nnnnnnnn (21 bits) */
243		return(3);
244	} else if (n < 0x10000000) {
245		/* 1110nnnn nnnnnnnn nnnnnnnn nnnnnnnn (28 bits) */
246		return(4);
247	} else {
248		/* 11110000 nnnnnnnn nnnnnnnn nnnnnnnn nnnnnnnn (32 bits) */
249		return(5);
250	}
251}
252
253/*********************************************************//**
254Reads a ulint in a compressed form.
255@return read integer (< 2^32) */
256UNIV_INLINE
257ulint
258mach_read_compressed(
259/*=================*/
260	const byte*	b)	/*!< in: pointer to memory from where to read */
261{
262	ulint	val;
263
264	val = mach_read_from_1(b);
265
266	if (val < 0x80) {
267		/* 0nnnnnnn (7 bits) */
268	} else if (val < 0xC0) {
269		/* 10nnnnnn nnnnnnnn (14 bits) */
270		val = mach_read_from_2(b) & 0x3FFF;
271		ut_ad(val > 0x7F);
272	} else if (val < 0xE0) {
273		/* 110nnnnn nnnnnnnn nnnnnnnn (21 bits) */
274		val = mach_read_from_3(b) & 0x1FFFFF;
275		ut_ad(val > 0x3FFF);
276	} else if (val < 0xF0) {
277		/* 1110nnnn nnnnnnnn nnnnnnnn nnnnnnnn (28 bits) */
278		val = mach_read_from_4(b) & 0xFFFFFFF;
279		ut_ad(val > 0x1FFFFF);
280	} else {
281		/* 11110000 nnnnnnnn nnnnnnnn nnnnnnnn nnnnnnnn (32 bits) */
282		ut_ad(val == 0xF0);
283		val = mach_read_from_4(b + 1);
284		ut_ad(val > 0xFFFFFFF);
285	}
286
287	return(val);
288}
289
290/** Read a 32-bit integer in a compressed form.
291@param[in,out]	b	pointer to memory where to read;
292advanced by the number of bytes consumed
293@return unsigned value */
294UNIV_INLINE
295ib_uint32_t
296mach_read_next_compressed(
297	const byte**	b)
298{
299	ulint	val = mach_read_from_1(*b);
300
301	if (val < 0x80) {
302		/* 0nnnnnnn (7 bits) */
303		++*b;
304	} else if (val < 0xC0) {
305		/* 10nnnnnn nnnnnnnn (14 bits) */
306		val = mach_read_from_2(*b) & 0x3FFF;
307		ut_ad(val > 0x7F);
308		*b += 2;
309	} else if (val < 0xE0) {
310		/* 110nnnnn nnnnnnnn nnnnnnnn (21 bits) */
311		val = mach_read_from_3(*b) & 0x1FFFFF;
312		ut_ad(val > 0x3FFF);
313		*b += 3;
314	} else if (val < 0xF0) {
315		/* 1110nnnn nnnnnnnn nnnnnnnn nnnnnnnn (28 bits) */
316		val = mach_read_from_4(*b) & 0xFFFFFFF;
317		ut_ad(val > 0x1FFFFF);
318		*b += 4;
319	} else {
320		/* 11110000 nnnnnnnn nnnnnnnn nnnnnnnn nnnnnnnn (32 bits) */
321		ut_ad(val == 0xF0);
322		val = mach_read_from_4(*b + 1);
323		ut_ad(val > 0xFFFFFFF);
324		*b += 5;
325	}
326
327	return(static_cast<ib_uint32_t>(val));
328}
329
330/*******************************************************//**
331The following function is used to store data in 8 consecutive
332bytes. We store the most significant byte to the lowest address. */
333UNIV_INLINE
334void
335mach_write_to_8(
336/*============*/
337	void*		b,	/*!< in: pointer to 8 bytes where to store */
338	ib_uint64_t	n)	/*!< in: 64-bit integer to be stored */
339{
340	mach_write_to_4(static_cast<byte*>(b), (ulint) (n >> 32));
341	mach_write_to_4(static_cast<byte*>(b) + 4, (ulint) n);
342}
343
344#endif /* !UNIV_INNOCHECKSUM */
345
346/********************************************************//**
347The following function is used to fetch data from 8 consecutive
348bytes. The most significant byte is at the lowest address.
349@return 64-bit integer */
350UNIV_INLINE
351ib_uint64_t
352mach_read_from_8(
353/*=============*/
354	const byte*	b)	/*!< in: pointer to 8 bytes */
355{
356	ib_uint64_t	u64;
357
358	u64 = mach_read_from_4(b);
359	u64 <<= 32;
360	u64 |= mach_read_from_4(b + 4);
361
362	return(u64);
363}
364
365#ifndef UNIV_INNOCHECKSUM
366
367/*******************************************************//**
368The following function is used to store data in 7 consecutive
369bytes. We store the most significant byte to the lowest address. */
370UNIV_INLINE
371void
372mach_write_to_7(
373/*============*/
374	byte*		b,	/*!< in: pointer to 7 bytes where to store */
375	ib_uint64_t	n)	/*!< in: 56-bit integer */
376{
377	mach_write_to_3(b, (ulint) (n >> 32));
378	mach_write_to_4(b + 3, (ulint) n);
379}
380
381/********************************************************//**
382The following function is used to fetch data from 7 consecutive
383bytes. The most significant byte is at the lowest address.
384@return 56-bit integer */
385UNIV_INLINE
386ib_uint64_t
387mach_read_from_7(
388/*=============*/
389	const byte*	b)	/*!< in: pointer to 7 bytes */
390{
391	return(ut_ull_create(mach_read_from_3(b), mach_read_from_4(b + 3)));
392}
393
394/*******************************************************//**
395The following function is used to store data in 6 consecutive
396bytes. We store the most significant byte to the lowest address. */
397UNIV_INLINE
398void
399mach_write_to_6(
400/*============*/
401	byte*		b,	/*!< in: pointer to 6 bytes where to store */
402	ib_uint64_t	n)	/*!< in: 48-bit integer */
403{
404	mach_write_to_2(b, (ulint) (n >> 32));
405	mach_write_to_4(b + 2, (ulint) n);
406}
407
408/********************************************************//**
409The following function is used to fetch data from 6 consecutive
410bytes. The most significant byte is at the lowest address.
411@return 48-bit integer */
412UNIV_INLINE
413ib_uint64_t
414mach_read_from_6(
415/*=============*/
416	const byte*	b)	/*!< in: pointer to 6 bytes */
417{
418	return(ut_ull_create(mach_read_from_2(b), mach_read_from_4(b + 2)));
419}
420
421/*********************************************************//**
422Writes a 64-bit integer in a compressed form (5..9 bytes).
423@return size in bytes */
424UNIV_INLINE
425ulint
426mach_u64_write_compressed(
427/*======================*/
428	byte*		b,	/*!< in: pointer to memory where to store */
429	ib_uint64_t	n)	/*!< in: 64-bit integer to be stored */
430{
431	ulint	size = mach_write_compressed(b, (ulint) (n >> 32));
432	mach_write_to_4(b + size, (ulint) n);
433
434	return(size + 4);
435}
436
437/** Read a 64-bit integer in a compressed form.
438@param[in,out]	b	pointer to memory where to read;
439advanced by the number of bytes consumed
440@return unsigned value */
441UNIV_INLINE
442ib_uint64_t
443mach_u64_read_next_compressed(
444	const byte**	b)
445{
446	ib_uint64_t	val;
447
448	val = mach_read_next_compressed(b);
449	val <<= 32;
450	val |= mach_read_from_4(*b);
451	*b += 4;
452	return(val);
453}
454
455/*********************************************************//**
456Writes a 64-bit integer in a compressed form (1..11 bytes).
457@return size in bytes */
458UNIV_INLINE
459ulint
460mach_u64_write_much_compressed(
461/*===========================*/
462	byte*		b,	/*!< in: pointer to memory where to store */
463	ib_uint64_t	n)	/*!< in: 64-bit integer to be stored */
464{
465	ulint	size;
466
467	if (!(n >> 32)) {
468		return(mach_write_compressed(b, (ulint) n));
469	}
470
471	*b = (byte)0xFF;
472	size = 1 + mach_write_compressed(b + 1, (ulint) (n >> 32));
473
474	size += mach_write_compressed(b + size, (ulint) n & 0xFFFFFFFF);
475
476	return(size);
477}
478
479/*********************************************************//**
480Reads a 64-bit integer in a compressed form.
481@return the value read */
482UNIV_INLINE
483ib_uint64_t
484mach_u64_read_much_compressed(
485/*==========================*/
486	const byte*	b)	/*!< in: pointer to memory from where to read */
487{
488	ib_uint64_t	n;
489
490	if (*b != 0xFF) {
491		return(mach_read_compressed(b));
492	}
493
494	b++;
495	n = mach_read_next_compressed(&b);
496	n <<= 32;
497	n |= mach_read_compressed(b);
498
499	return(n);
500}
501
502/** Read a 64-bit integer in a compressed form.
503@param[in,out]	b	pointer to memory where to read;
504advanced by the number of bytes consumed
505@return unsigned value */
506UNIV_INLINE
507ib_uint64_t
508mach_read_next_much_compressed(
509	const byte**	b)
510{
511	ib_uint64_t	val = mach_read_from_1(*b);
512
513	if (val < 0x80) {
514		/* 0nnnnnnn (7 bits) */
515		++*b;
516	} else if (val < 0xC0) {
517		/* 10nnnnnn nnnnnnnn (14 bits) */
518		val = mach_read_from_2(*b) & 0x3FFF;
519		ut_ad(val > 0x7F);
520		*b += 2;
521	} else if (val < 0xE0) {
522		/* 110nnnnn nnnnnnnn nnnnnnnn (21 bits) */
523		val = mach_read_from_3(*b) & 0x1FFFFF;
524		ut_ad(val > 0x3FFF);
525		*b += 3;
526	} else if (val < 0xF0) {
527		/* 1110nnnn nnnnnnnn nnnnnnnn nnnnnnnn (28 bits) */
528		val = mach_read_from_4(*b) & 0xFFFFFFF;
529		ut_ad(val > 0x1FFFFF);
530		*b += 4;
531	} else if (val == 0xF0) {
532		/* 11110000 nnnnnnnn nnnnnnnn nnnnnnnn nnnnnnnn (32 bits) */
533		val = mach_read_from_4(*b + 1);
534		ut_ad(val > 0xFFFFFFF);
535		*b += 5;
536	} else {
537		/* 11111111 followed by up to 64 bits */
538		ut_ad(val == 0xFF);
539		++*b;
540		val = mach_read_next_compressed(b);
541		ut_ad(val > 0);
542		val <<= 32;
543		val |= mach_read_next_compressed(b);
544	}
545
546	return(val);
547}
548
549/*********************************************************//**
550Reads a double. It is stored in a little-endian format.
551@return double read */
552UNIV_INLINE
553double
554mach_double_read(
555/*=============*/
556	const byte*	b)	/*!< in: pointer to memory from where to read */
557{
558	double	d;
559	ulint	i;
560	byte*	ptr;
561
562	ptr = (byte*) &d;
563
564	for (i = 0; i < sizeof(double); i++) {
565#ifdef WORDS_BIGENDIAN
566		ptr[sizeof(double) - i - 1] = b[i];
567#else
568		ptr[i] = b[i];
569#endif
570	}
571
572	return(d);
573}
574
575/*********************************************************//**
576Writes a double. It is stored in a little-endian format. */
577UNIV_INLINE
578void
579mach_double_write(
580/*==============*/
581	byte*	b,	/*!< in: pointer to memory where to write */
582	double	d)	/*!< in: double */
583{
584	ulint	i;
585	byte*	ptr;
586
587	ptr = (byte*) &d;
588
589	for (i = 0; i < sizeof(double); i++) {
590#ifdef WORDS_BIGENDIAN
591		b[i] = ptr[sizeof(double) - i - 1];
592#else
593		b[i] = ptr[i];
594#endif
595	}
596}
597
598/*********************************************************//**
599Reads a float. It is stored in a little-endian format.
600@return float read */
601UNIV_INLINE
602float
603mach_float_read(
604/*============*/
605	const byte*	b)	/*!< in: pointer to memory from where to read */
606{
607	float	d;
608	ulint	i;
609	byte*	ptr;
610
611	ptr = (byte*) &d;
612
613	for (i = 0; i < sizeof(float); i++) {
614#ifdef WORDS_BIGENDIAN
615		ptr[sizeof(float) - i - 1] = b[i];
616#else
617		ptr[i] = b[i];
618#endif
619	}
620
621	return(d);
622}
623
624/*********************************************************//**
625Writes a float. It is stored in a little-endian format. */
626UNIV_INLINE
627void
628mach_float_write(
629/*=============*/
630	byte*	b,	/*!< in: pointer to memory where to write */
631	float	d)	/*!< in: float */
632{
633	ulint	i;
634	byte*	ptr;
635
636	ptr = (byte*) &d;
637
638	for (i = 0; i < sizeof(float); i++) {
639#ifdef WORDS_BIGENDIAN
640		b[i] = ptr[sizeof(float) - i - 1];
641#else
642		b[i] = ptr[i];
643#endif
644	}
645}
646
647/*********************************************************//**
648Reads a ulint stored in the little-endian format.
649@return unsigned long int */
650UNIV_INLINE
651ulint
652mach_read_from_n_little_endian(
653/*===========================*/
654	const byte*	buf,		/*!< in: from where to read */
655	ulint		buf_size)	/*!< in: from how many bytes to read */
656{
657	ulint	n	= 0;
658	const byte*	ptr;
659
660	ut_ad(buf_size > 0);
661
662	ptr = buf + buf_size;
663
664	for (;;) {
665		ptr--;
666
667		n = n << 8;
668
669		n += (ulint)(*ptr);
670
671		if (ptr == buf) {
672			break;
673		}
674	}
675
676	return(n);
677}
678
679/*********************************************************//**
680Writes a ulint in the little-endian format. */
681UNIV_INLINE
682void
683mach_write_to_n_little_endian(
684/*==========================*/
685	byte*	dest,		/*!< in: where to write */
686	ulint	dest_size,	/*!< in: into how many bytes to write */
687	ulint	n)		/*!< in: unsigned long int to write */
688{
689	byte*	end;
690
691	ut_ad(dest_size <= sizeof(ulint));
692	ut_ad(dest_size > 0);
693
694	end = dest + dest_size;
695
696	for (;;) {
697		*dest = (byte)(n & 0xFF);
698
699		n = n >> 8;
700
701		dest++;
702
703		if (dest == end) {
704			break;
705		}
706	}
707
708	ut_ad(n == 0);
709}
710
711/*********************************************************//**
712Reads a ulint stored in the little-endian format.
713@return unsigned long int */
714UNIV_INLINE
715ulint
716mach_read_from_2_little_endian(
717/*===========================*/
718	const byte*	buf)		/*!< in: from where to read */
719{
720	return((ulint)(buf[0]) | ((ulint)(buf[1]) << 8));
721}
722
723/*********************************************************//**
724Writes a ulint in the little-endian format. */
725UNIV_INLINE
726void
727mach_write_to_2_little_endian(
728/*==========================*/
729	byte*	dest,		/*!< in: where to write */
730	ulint	n)		/*!< in: unsigned long int to write */
731{
732	ut_ad(n < 256 * 256);
733
734	*dest = (byte)(n & 0xFFUL);
735
736	n = n >> 8;
737	dest++;
738
739	*dest = (byte)(n & 0xFFUL);
740}
741
742/*********************************************************//**
743Convert integral type from storage byte order (big endian) to
744host byte order.
745@return integer value */
746UNIV_INLINE
747ib_uint64_t
748mach_read_int_type(
749/*===============*/
750	const byte*	src,		/*!< in: where to read from */
751	ulint		len,		/*!< in: length of src */
752	ibool		unsigned_type)	/*!< in: signed or unsigned flag */
753{
754	/* XXX this can be optimized on big-endian machines */
755
756	uintmax_t	ret;
757	uint		i;
758
759	if (unsigned_type || (src[0] & 0x80)) {
760
761		ret = 0x0000000000000000ULL;
762	} else {
763
764		ret = 0xFFFFFFFFFFFFFF00ULL;
765	}
766
767	if (unsigned_type) {
768
769		ret |= src[0];
770	} else {
771
772		ret |= src[0] ^ 0x80;
773	}
774
775	for (i = 1; i < len; i++) {
776		ret <<= 8;
777		ret |= src[i];
778	}
779
780	return(ret);
781}
782/*********************************************************//**
783Swap byte ordering. */
784UNIV_INLINE
785void
786mach_swap_byte_order(
787/*=================*/
788        byte*           dest,           /*!< out: where to write */
789        const byte*     from,           /*!< in: where to read from */
790        ulint           len)            /*!< in: length of src */
791{
792        ut_ad(len > 0);
793        ut_ad(len <= 8);
794
795        dest += len;
796
797        switch (len & 0x7) {
798        case 0: *--dest = *from++; /* fall through */
799        case 7: *--dest = *from++; /* fall through */
800        case 6: *--dest = *from++; /* fall through */
801        case 5: *--dest = *from++; /* fall through */
802        case 4: *--dest = *from++; /* fall through */
803        case 3: *--dest = *from++; /* fall through */
804        case 2: *--dest = *from++; /* fall through */
805        case 1: *--dest = *from;
806        }
807}
808
809/*************************************************************
810Convert a ulonglong integer from host byte order to (big-endian)
811storage byte order. */
812UNIV_INLINE
813void
814mach_write_ulonglong(
815/*=================*/
816	byte*		dest,		/*!< in: where to write */
817	ulonglong	src,		/*!< in: where to read from */
818	ulint		len,		/*!< in: length of dest */
819	bool		usign)		/*!< in: signed or unsigned flag */
820{
821	byte*		ptr = reinterpret_cast<byte*>(&src);
822
823	ut_ad(len <= sizeof(ulonglong));
824
825#ifdef WORDS_BIGENDIAN
826	memcpy(dest, ptr + (sizeof(src) - len), len);
827#else
828	mach_swap_byte_order(dest, reinterpret_cast<byte*>(ptr), len);
829#endif /* WORDS_BIGENDIAN */
830
831	if (!usign) {
832		*dest ^=  0x80;
833	}
834}
835
836#endif /* !UNIV_INNOCHECKSUM */
837