]>
| Commit | Line | Data |
|---|---|---|
| 959ef981 | 1 | // SPDX-License-Identifier: GPL-2.0 |
| 2bd0ea18 | 2 | /* |
| da23017d NS |
3 | * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. |
| 4 | * All Rights Reserved. | |
| 2bd0ea18 NS |
5 | */ |
| 6 | ||
| 6b803e5a | 7 | #include "libxfs.h" |
| 2bd0ea18 NS |
8 | #include "bit.h" |
| 9 | ||
| 984af2e1 DW |
10 | int |
| 11 | getbit_l( | |
| 2bd0ea18 NS |
12 | char *ptr, |
| 13 | int bit) | |
| 14 | { | |
| 15 | int mask; | |
| 16 | int shift; | |
| 17 | ||
| 18 | ptr += byteize(bit); | |
| 19 | bit = bitoffs(bit); | |
| 20 | shift = 7 - bit; | |
| 21 | mask = 1 << shift; | |
| 22 | return (*ptr & mask) >> shift; | |
| 23 | } | |
| 24 | ||
| 984af2e1 DW |
25 | void |
| 26 | setbit_l( | |
| 2bd0ea18 NS |
27 | char *ptr, |
| 28 | int bit, | |
| 29 | int val) | |
| 30 | { | |
| 31 | int mask; | |
| 32 | int shift; | |
| 33 | ||
| 34 | ptr += byteize(bit); | |
| 35 | bit = bitoffs(bit); | |
| 36 | shift = 7 - bit; | |
| 37 | mask = (1 << shift); | |
| 38 | if (val) { | |
| 39 | *ptr |= mask; | |
| 40 | } else { | |
| 41 | mask = ~mask; | |
| 42 | *ptr &= mask; | |
| 43 | } | |
| 44 | } | |
| 45 | ||
| 14f8b681 | 46 | int64_t |
| 2bd0ea18 NS |
47 | getbitval( |
| 48 | void *obj, | |
| 49 | int bitoff, | |
| 50 | int nbits, | |
| 51 | int flags) | |
| 52 | { | |
| 53 | int bit; | |
| 54 | int i; | |
| 55 | char *p; | |
| 14f8b681 | 56 | int64_t rval; |
| 2bd0ea18 | 57 | int signext; |
| dfc130f3 RC |
58 | |
| 59 | ASSERT(nbits<=64); | |
| 2bd0ea18 NS |
60 | |
| 61 | p = (char *)obj + byteize(bitoff); | |
| 62 | bit = bitoffs(bitoff); | |
| 63 | signext = (flags & BVSIGNED) != 0; | |
| 221bfd06 DW |
64 | |
| 65 | if (bit != 0) | |
| 66 | goto scrape_bits; | |
| 67 | ||
| 68 | switch (nbits) { | |
| 69 | case 64: | |
| 70 | return get_unaligned_be64(p); | |
| 71 | case 32: | |
| 2bd0ea18 | 72 | if (signext) |
| 221bfd06 DW |
73 | return (__s32)get_unaligned_be32(p); |
| 74 | return (__u32)get_unaligned_be32(p); | |
| 75 | case 16: | |
| 2bd0ea18 | 76 | if (signext) |
| 221bfd06 DW |
77 | return (__s16)get_unaligned_be16(p); |
| 78 | return (__u16)get_unaligned_be16(p); | |
| 79 | case 8: | |
| 2bd0ea18 | 80 | if (signext) |
| 5e656dbb | 81 | return *(__s8 *)p; |
| 221bfd06 | 82 | return *(__u8 *)p; |
| 2bd0ea18 | 83 | } |
| dfc130f3 | 84 | |
| 221bfd06 | 85 | scrape_bits: |
| 2bd0ea18 | 86 | for (i = 0, rval = 0LL; i < nbits; i++) { |
| 984af2e1 | 87 | if (getbit_l(p, bit + i)) { |
| dfc130f3 RC |
88 | /* If the last bit is on and we care about sign |
| 89 | * bits and we don't have a full 64 bit | |
| 90 | * container, turn all bits on between the | |
| 91 | * sign bit and the most sig bit. | |
| 92 | */ | |
| 93 | ||
| 94 | /* handle endian swap here */ | |
| 2bd0ea18 NS |
95 | #if __BYTE_ORDER == LITTLE_ENDIAN |
| 96 | if (i == 0 && signext && nbits < 64) | |
| a93fcc04 | 97 | rval = (~0ULL) << nbits; |
| 25f9772a | 98 | rval |= 1ULL << (nbits - i - 1); |
| 2bd0ea18 NS |
99 | #else |
| 100 | if ((i == (nbits - 1)) && signext && nbits < 64) | |
| a93fcc04 | 101 | rval |= ((~0ULL) << nbits); |
| 25f9772a | 102 | rval |= 1ULL << (nbits - i - 1); |
| 2bd0ea18 NS |
103 | #endif |
| 104 | } | |
| 105 | } | |
| 106 | return rval; | |
| 107 | } | |
| 108 | ||
| dc151328 MT |
109 | /* |
| 110 | * The input data can be 8, 16, 32, and 64 sized numeric values | |
| 111 | * aligned on a byte boundry, or odd sized numbers stored on odd | |
| 112 | * aligned offset (for example the bmbt fields). | |
| 113 | * | |
| 114 | * The input data sent to this routine has been converted to big endian | |
| 115 | * and has been adjusted in the array so that the first input bit is to | |
| 116 | * be written in the first bit in the output. | |
| 117 | * | |
| 118 | * If the field length and the output buffer are byte aligned, then use | |
| 119 | * memcpy from the input to the output, but if either entries are not byte | |
| 120 | * aligned, then loop over the entire bit range reading the input value | |
| 121 | * and set/clear the matching bit in the output. | |
| 122 | * | |
| 123 | * example when ibuf is not multiple of a byte in length: | |
| 124 | * | |
| 125 | * ibuf: | BBBBBBBB | bbbxxxxx | | |
| 126 | * \\\\\\\\--\\\\ | |
| 127 | * obuf+bitoff: | xBBBBBBB | Bbbbxxxx | | |
| 128 | * | |
| 129 | */ | |
| 2bd0ea18 NS |
130 | void |
| 131 | setbitval( | |
| dc151328 MT |
132 | void *obuf, /* start of buffer to write into */ |
| 133 | int bitoff, /* bit offset into the output buffer */ | |
| 134 | int nbits, /* number of bits to write */ | |
| 135 | void *ibuf) /* source bits */ | |
| 2bd0ea18 | 136 | { |
| dc151328 MT |
137 | char *in = ibuf; |
| 138 | char *out = obuf; | |
| 139 | int bit; | |
| 140 | ||
| 141 | if (bitoff % NBBY || nbits % NBBY) { | |
| 142 | for (bit = 0; bit < nbits; bit++) | |
| 984af2e1 | 143 | setbit_l(out, bit + bitoff, getbit_l(in, bit)); |
| dc151328 MT |
144 | } else |
| 145 | memcpy(out + byteize(bitoff), in, byteize(nbits)); | |
| 2bd0ea18 | 146 | } |