1 | /***************************************************************************** |
2 | |
3 | Copyright (c) 1995, 2015, Oracle and/or its affiliates. All Rights Reserved. |
4 | Copyright (c) 2017, MariaDB Corporation. |
5 | |
6 | This program is free software; you can redistribute it and/or modify it under |
7 | the terms of the GNU General Public License as published by the Free Software |
8 | Foundation; version 2 of the License. |
9 | |
10 | This program is distributed in the hope that it will be useful, but WITHOUT |
11 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
12 | FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. |
13 | |
14 | You should have received a copy of the GNU General Public License along with |
15 | this program; if not, write to the Free Software Foundation, Inc., |
16 | 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA |
17 | |
18 | *****************************************************************************/ |
19 | |
20 | /******************************************************************//** |
21 | @file include/mach0data.ic |
22 | Utilities for converting data from the database file |
23 | to the machine format. |
24 | |
25 | Created 11/28/1995 Heikki Tuuri |
26 | ***********************************************************************/ |
27 | |
28 | #ifndef UNIV_INNOCHECKSUM |
29 | |
30 | #include "mtr0types.h" |
31 | |
32 | /*******************************************************//** |
33 | The following function is used to store data in one byte. */ |
34 | UNIV_INLINE |
35 | void |
36 | mach_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 | /*******************************************************//** |
49 | The following function is used to store data in two consecutive |
50 | bytes. We store the most significant byte to the lowest address. */ |
51 | UNIV_INLINE |
52 | void |
53 | mach_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 */ |
67 | UNIV_INLINE |
68 | uint8_t |
69 | mach_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 |
76 | bytes. 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 */ |
79 | UNIV_INLINE |
80 | uint16_t |
81 | mach_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 | /********************************************************//** |
90 | The following function is used to convert a 16-bit data item |
91 | to the canonical format, for fast bytewise equality test |
92 | against memory. |
93 | @return 16-bit integer in canonical format */ |
94 | UNIV_INLINE |
95 | uint16 |
96 | mach_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 | /********************************************************//** |
106 | The following function is used to convert a 16-bit data item |
107 | from the canonical format, for fast bytewise equality test |
108 | against memory. |
109 | @return integer in machine-dependent format */ |
110 | UNIV_INLINE |
111 | ulint |
112 | mach_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 | /*******************************************************//** |
121 | The following function is used to store data in 3 consecutive |
122 | bytes. We store the most significant byte to the lowest address. */ |
123 | UNIV_INLINE |
124 | void |
125 | mach_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 |
138 | bytes. The most significant byte is at the lowest address. |
139 | @param[in] b pointer to 3 bytes to read |
140 | @return uint32_t integer */ |
141 | UNIV_INLINE |
142 | uint32_t |
143 | mach_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 | /*******************************************************//** |
154 | The following function is used to store data in four consecutive |
155 | bytes. We store the most significant byte to the lowest address. */ |
156 | UNIV_INLINE |
157 | void |
158 | mach_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 |
170 | bytes. The most significant byte is at the lowest address. |
171 | @param[in] b pointer to 4 bytes to read |
172 | @return 32 bit integer */ |
173 | UNIV_INLINE |
174 | uint32_t |
175 | mach_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 | /*********************************************************//** |
188 | Writes a ulint in a compressed form where the first byte codes the |
189 | length of the stored ulint. We look at the most significant bits of |
190 | the byte. If the most significant bit is zero, it means 1-byte storage, |
191 | else if the 2nd bit is 0, it means 2-byte storage, else if 3rd is 0, |
192 | it means 3-byte storage, else if 4th is 0, it means 4-byte storage, |
193 | else the storage is 5-byte. |
194 | @return compressed size in bytes */ |
195 | UNIV_INLINE |
196 | ulint |
197 | mach_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 | /*********************************************************//** |
227 | Returns the size of a ulint when written in the compressed form. |
228 | @return compressed size in bytes */ |
229 | UNIV_INLINE |
230 | ulint |
231 | mach_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 | /*********************************************************//** |
254 | Reads a ulint in a compressed form. |
255 | @return read integer (< 2^32) */ |
256 | UNIV_INLINE |
257 | ulint |
258 | mach_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; |
292 | advanced by the number of bytes consumed |
293 | @return unsigned value */ |
294 | UNIV_INLINE |
295 | ib_uint32_t |
296 | mach_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 | /*******************************************************//** |
331 | The following function is used to store data in 8 consecutive |
332 | bytes. We store the most significant byte to the lowest address. */ |
333 | UNIV_INLINE |
334 | void |
335 | mach_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 | /********************************************************//** |
347 | The following function is used to fetch data from 8 consecutive |
348 | bytes. The most significant byte is at the lowest address. |
349 | @return 64-bit integer */ |
350 | UNIV_INLINE |
351 | ib_uint64_t |
352 | mach_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 | /*******************************************************//** |
368 | The following function is used to store data in 7 consecutive |
369 | bytes. We store the most significant byte to the lowest address. */ |
370 | UNIV_INLINE |
371 | void |
372 | mach_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 | /********************************************************//** |
382 | The following function is used to fetch data from 7 consecutive |
383 | bytes. The most significant byte is at the lowest address. |
384 | @return 56-bit integer */ |
385 | UNIV_INLINE |
386 | ib_uint64_t |
387 | mach_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 | /*******************************************************//** |
395 | The following function is used to store data in 6 consecutive |
396 | bytes. We store the most significant byte to the lowest address. */ |
397 | UNIV_INLINE |
398 | void |
399 | mach_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 | /********************************************************//** |
409 | The following function is used to fetch data from 6 consecutive |
410 | bytes. The most significant byte is at the lowest address. |
411 | @return 48-bit integer */ |
412 | UNIV_INLINE |
413 | ib_uint64_t |
414 | mach_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 | /*********************************************************//** |
422 | Writes a 64-bit integer in a compressed form (5..9 bytes). |
423 | @return size in bytes */ |
424 | UNIV_INLINE |
425 | ulint |
426 | mach_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; |
439 | advanced by the number of bytes consumed |
440 | @return unsigned value */ |
441 | UNIV_INLINE |
442 | ib_uint64_t |
443 | mach_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 | /*********************************************************//** |
456 | Writes a 64-bit integer in a compressed form (1..11 bytes). |
457 | @return size in bytes */ |
458 | UNIV_INLINE |
459 | ulint |
460 | mach_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 | /*********************************************************//** |
480 | Reads a 64-bit integer in a compressed form. |
481 | @return the value read */ |
482 | UNIV_INLINE |
483 | ib_uint64_t |
484 | mach_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; |
504 | advanced by the number of bytes consumed |
505 | @return unsigned value */ |
506 | UNIV_INLINE |
507 | ib_uint64_t |
508 | mach_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 | /** Read a 64-bit integer in a compressed form. |
550 | @param[in,out] ptr pointer to memory where to read; |
551 | advanced by the number of bytes consumed, or set NULL if out of space |
552 | @param[in] end_ptr end of the buffer |
553 | @return unsigned value */ |
554 | UNIV_INLINE |
555 | ib_uint64_t |
556 | mach_u64_parse_compressed( |
557 | const byte** ptr, |
558 | const byte* end_ptr) |
559 | { |
560 | ib_uint64_t val = 0; |
561 | |
562 | if (end_ptr < *ptr + 5) { |
563 | *ptr = NULL; |
564 | return(val); |
565 | } |
566 | |
567 | val = mach_read_next_compressed(ptr); |
568 | |
569 | if (end_ptr < *ptr + 4) { |
570 | *ptr = NULL; |
571 | return(val); |
572 | } |
573 | |
574 | val <<= 32; |
575 | val |= mach_read_from_4(*ptr); |
576 | *ptr += 4; |
577 | |
578 | return(val); |
579 | } |
580 | |
581 | /*********************************************************//** |
582 | Reads a double. It is stored in a little-endian format. |
583 | @return double read */ |
584 | UNIV_INLINE |
585 | double |
586 | mach_double_read( |
587 | /*=============*/ |
588 | const byte* b) /*!< in: pointer to memory from where to read */ |
589 | { |
590 | double d; |
591 | ulint i; |
592 | byte* ptr; |
593 | |
594 | ptr = (byte*) &d; |
595 | |
596 | for (i = 0; i < sizeof(double); i++) { |
597 | #ifdef WORDS_BIGENDIAN |
598 | ptr[sizeof(double) - i - 1] = b[i]; |
599 | #else |
600 | ptr[i] = b[i]; |
601 | #endif |
602 | } |
603 | |
604 | return(d); |
605 | } |
606 | |
607 | /*********************************************************//** |
608 | Writes a double. It is stored in a little-endian format. */ |
609 | UNIV_INLINE |
610 | void |
611 | mach_double_write( |
612 | /*==============*/ |
613 | byte* b, /*!< in: pointer to memory where to write */ |
614 | double d) /*!< in: double */ |
615 | { |
616 | ulint i; |
617 | byte* ptr; |
618 | |
619 | ptr = (byte*) &d; |
620 | |
621 | for (i = 0; i < sizeof(double); i++) { |
622 | #ifdef WORDS_BIGENDIAN |
623 | b[i] = ptr[sizeof(double) - i - 1]; |
624 | #else |
625 | b[i] = ptr[i]; |
626 | #endif |
627 | } |
628 | } |
629 | |
630 | /*********************************************************//** |
631 | Reads a float. It is stored in a little-endian format. |
632 | @return float read */ |
633 | UNIV_INLINE |
634 | float |
635 | mach_float_read( |
636 | /*============*/ |
637 | const byte* b) /*!< in: pointer to memory from where to read */ |
638 | { |
639 | float d; |
640 | ulint i; |
641 | byte* ptr; |
642 | |
643 | ptr = (byte*) &d; |
644 | |
645 | for (i = 0; i < sizeof(float); i++) { |
646 | #ifdef WORDS_BIGENDIAN |
647 | ptr[sizeof(float) - i - 1] = b[i]; |
648 | #else |
649 | ptr[i] = b[i]; |
650 | #endif |
651 | } |
652 | |
653 | return(d); |
654 | } |
655 | |
656 | /*********************************************************//** |
657 | Writes a float. It is stored in a little-endian format. */ |
658 | UNIV_INLINE |
659 | void |
660 | mach_float_write( |
661 | /*=============*/ |
662 | byte* b, /*!< in: pointer to memory where to write */ |
663 | float d) /*!< in: float */ |
664 | { |
665 | ulint i; |
666 | byte* ptr; |
667 | |
668 | ptr = (byte*) &d; |
669 | |
670 | for (i = 0; i < sizeof(float); i++) { |
671 | #ifdef WORDS_BIGENDIAN |
672 | b[i] = ptr[sizeof(float) - i - 1]; |
673 | #else |
674 | b[i] = ptr[i]; |
675 | #endif |
676 | } |
677 | } |
678 | |
679 | /*********************************************************//** |
680 | Reads a ulint stored in the little-endian format. |
681 | @return unsigned long int */ |
682 | UNIV_INLINE |
683 | ulint |
684 | mach_read_from_n_little_endian( |
685 | /*===========================*/ |
686 | const byte* buf, /*!< in: from where to read */ |
687 | ulint buf_size) /*!< in: from how many bytes to read */ |
688 | { |
689 | ulint n = 0; |
690 | const byte* ptr; |
691 | |
692 | ut_ad(buf_size > 0); |
693 | |
694 | ptr = buf + buf_size; |
695 | |
696 | for (;;) { |
697 | ptr--; |
698 | |
699 | n = n << 8; |
700 | |
701 | n += (ulint)(*ptr); |
702 | |
703 | if (ptr == buf) { |
704 | break; |
705 | } |
706 | } |
707 | |
708 | return(n); |
709 | } |
710 | |
711 | /*********************************************************//** |
712 | Writes a ulint in the little-endian format. */ |
713 | UNIV_INLINE |
714 | void |
715 | mach_write_to_n_little_endian( |
716 | /*==========================*/ |
717 | byte* dest, /*!< in: where to write */ |
718 | ulint dest_size, /*!< in: into how many bytes to write */ |
719 | ulint n) /*!< in: unsigned long int to write */ |
720 | { |
721 | byte* end; |
722 | |
723 | ut_ad(dest_size <= sizeof(ulint)); |
724 | ut_ad(dest_size > 0); |
725 | |
726 | end = dest + dest_size; |
727 | |
728 | for (;;) { |
729 | *dest = (byte)(n & 0xFF); |
730 | |
731 | n = n >> 8; |
732 | |
733 | dest++; |
734 | |
735 | if (dest == end) { |
736 | break; |
737 | } |
738 | } |
739 | |
740 | ut_ad(n == 0); |
741 | } |
742 | |
743 | /*********************************************************//** |
744 | Reads a ulint stored in the little-endian format. |
745 | @return unsigned long int */ |
746 | UNIV_INLINE |
747 | ulint |
748 | mach_read_from_2_little_endian( |
749 | /*===========================*/ |
750 | const byte* buf) /*!< in: from where to read */ |
751 | { |
752 | return((ulint)(buf[0]) | ((ulint)(buf[1]) << 8)); |
753 | } |
754 | |
755 | /*********************************************************//** |
756 | Writes a ulint in the little-endian format. */ |
757 | UNIV_INLINE |
758 | void |
759 | mach_write_to_2_little_endian( |
760 | /*==========================*/ |
761 | byte* dest, /*!< in: where to write */ |
762 | ulint n) /*!< in: unsigned long int to write */ |
763 | { |
764 | ut_ad(n < 256 * 256); |
765 | |
766 | *dest = (byte)(n & 0xFFUL); |
767 | |
768 | n = n >> 8; |
769 | dest++; |
770 | |
771 | *dest = (byte)(n & 0xFFUL); |
772 | } |
773 | |
774 | /*********************************************************//** |
775 | Convert integral type from storage byte order (big endian) to |
776 | host byte order. |
777 | @return integer value */ |
778 | UNIV_INLINE |
779 | ib_uint64_t |
780 | mach_read_int_type( |
781 | /*===============*/ |
782 | const byte* src, /*!< in: where to read from */ |
783 | ulint len, /*!< in: length of src */ |
784 | ibool unsigned_type) /*!< in: signed or unsigned flag */ |
785 | { |
786 | /* XXX this can be optimized on big-endian machines */ |
787 | |
788 | uintmax_t ret; |
789 | uint i; |
790 | |
791 | if (unsigned_type || (src[0] & 0x80)) { |
792 | |
793 | ret = 0x0000000000000000ULL; |
794 | } else { |
795 | |
796 | ret = 0xFFFFFFFFFFFFFF00ULL; |
797 | } |
798 | |
799 | if (unsigned_type) { |
800 | |
801 | ret |= src[0]; |
802 | } else { |
803 | |
804 | ret |= src[0] ^ 0x80; |
805 | } |
806 | |
807 | for (i = 1; i < len; i++) { |
808 | ret <<= 8; |
809 | ret |= src[i]; |
810 | } |
811 | |
812 | return(ret); |
813 | } |
814 | /*********************************************************//** |
815 | Swap byte ordering. */ |
816 | UNIV_INLINE |
817 | void |
818 | mach_swap_byte_order( |
819 | /*=================*/ |
820 | byte* dest, /*!< out: where to write */ |
821 | const byte* from, /*!< in: where to read from */ |
822 | ulint len) /*!< in: length of src */ |
823 | { |
824 | ut_ad(len > 0); |
825 | ut_ad(len <= 8); |
826 | |
827 | dest += len; |
828 | |
829 | switch (len & 0x7) { |
830 | case 0: *--dest = *from++; /* fall through */ |
831 | case 7: *--dest = *from++; /* fall through */ |
832 | case 6: *--dest = *from++; /* fall through */ |
833 | case 5: *--dest = *from++; /* fall through */ |
834 | case 4: *--dest = *from++; /* fall through */ |
835 | case 3: *--dest = *from++; /* fall through */ |
836 | case 2: *--dest = *from++; /* fall through */ |
837 | case 1: *--dest = *from; |
838 | } |
839 | } |
840 | |
841 | /************************************************************* |
842 | Convert a ulonglong integer from host byte order to (big-endian) |
843 | storage byte order. */ |
844 | UNIV_INLINE |
845 | void |
846 | mach_write_ulonglong( |
847 | /*=================*/ |
848 | byte* dest, /*!< in: where to write */ |
849 | ulonglong src, /*!< in: where to read from */ |
850 | ulint len, /*!< in: length of dest */ |
851 | bool usign) /*!< in: signed or unsigned flag */ |
852 | { |
853 | byte* ptr = reinterpret_cast<byte*>(&src); |
854 | |
855 | ut_ad(len <= sizeof(ulonglong)); |
856 | |
857 | #ifdef WORDS_BIGENDIAN |
858 | memcpy(dest, ptr + (sizeof(src) - len), len); |
859 | #else |
860 | mach_swap_byte_order(dest, reinterpret_cast<byte*>(ptr), len); |
861 | #endif /* WORDS_BIGENDIAN */ |
862 | |
863 | if (!usign) { |
864 | *dest ^= 0x80; |
865 | } |
866 | } |
867 | |
868 | #endif /* !UNIV_INNOCHECKSUM */ |
869 | |
870 | /** Read 1 to 4 bytes from a file page buffered in the buffer pool. |
871 | @param[in] ptr pointer where to read |
872 | @param[in] type MLOG_1BYTE, MLOG_2BYTES, or MLOG_4BYTES |
873 | @return value read */ |
874 | UNIV_INLINE |
875 | ulint |
876 | mach_read_ulint( |
877 | const byte* ptr, |
878 | mlog_id_t type) |
879 | { |
880 | switch (type) { |
881 | case MLOG_1BYTE: |
882 | return(mach_read_from_1(ptr)); |
883 | case MLOG_2BYTES: |
884 | return(mach_read_from_2(ptr)); |
885 | case MLOG_4BYTES: |
886 | return(mach_read_from_4(ptr)); |
887 | default: |
888 | break; |
889 | } |
890 | |
891 | ut_error; |
892 | return(0); |
893 | } |
894 | |