]>
Commit | Line | Data |
---|---|---|
1 | // SPDX-License-Identifier: GPL-2.0 | |
2 | /* | |
3 | * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. | |
4 | * All Rights Reserved. | |
5 | */ | |
6 | ||
7 | #include "libxfs.h" | |
8 | #include "bit.h" | |
9 | ||
10 | int | |
11 | getbit_l( | |
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 | ||
25 | void | |
26 | setbit_l( | |
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 | ||
46 | int64_t | |
47 | getbitval( | |
48 | void *obj, | |
49 | int bitoff, | |
50 | int nbits, | |
51 | int flags) | |
52 | { | |
53 | int bit; | |
54 | int i; | |
55 | char *p; | |
56 | int64_t rval; | |
57 | int signext; | |
58 | ||
59 | ASSERT(nbits<=64); | |
60 | ||
61 | p = (char *)obj + byteize(bitoff); | |
62 | bit = bitoffs(bitoff); | |
63 | signext = (flags & BVSIGNED) != 0; | |
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: | |
72 | if (signext) | |
73 | return (__s32)get_unaligned_be32(p); | |
74 | return (__u32)get_unaligned_be32(p); | |
75 | case 16: | |
76 | if (signext) | |
77 | return (__s16)get_unaligned_be16(p); | |
78 | return (__u16)get_unaligned_be16(p); | |
79 | case 8: | |
80 | if (signext) | |
81 | return *(__s8 *)p; | |
82 | return *(__u8 *)p; | |
83 | } | |
84 | ||
85 | scrape_bits: | |
86 | for (i = 0, rval = 0LL; i < nbits; i++) { | |
87 | if (getbit_l(p, bit + i)) { | |
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 */ | |
95 | #if __BYTE_ORDER == LITTLE_ENDIAN | |
96 | if (i == 0 && signext && nbits < 64) | |
97 | rval = (~0ULL) << nbits; | |
98 | rval |= 1ULL << (nbits - i - 1); | |
99 | #else | |
100 | if ((i == (nbits - 1)) && signext && nbits < 64) | |
101 | rval |= ((~0ULL) << nbits); | |
102 | rval |= 1ULL << (nbits - i - 1); | |
103 | #endif | |
104 | } | |
105 | } | |
106 | return rval; | |
107 | } | |
108 | ||
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 | */ | |
130 | void | |
131 | setbitval( | |
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 */ | |
136 | { | |
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++) | |
143 | setbit_l(out, bit + bitoff, getbit_l(in, bit)); | |
144 | } else | |
145 | memcpy(out + byteize(bitoff), in, byteize(nbits)); | |
146 | } |