]>
Commit | Line | Data |
---|---|---|
2bd0ea18 | 1 | /* |
da23017d NS |
2 | * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. |
3 | * All Rights Reserved. | |
dfc130f3 | 4 | * |
da23017d NS |
5 | * This program is free software; you can redistribute it and/or |
6 | * modify it under the terms of the GNU General Public License as | |
2bd0ea18 | 7 | * published by the Free Software Foundation. |
dfc130f3 | 8 | * |
da23017d NS |
9 | * This program is distributed in the hope that it would be useful, |
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
12 | * GNU General Public License for more details. | |
dfc130f3 | 13 | * |
da23017d NS |
14 | * You should have received a copy of the GNU General Public License |
15 | * along with this program; if not, write the Free Software Foundation, | |
16 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | |
2bd0ea18 NS |
17 | */ |
18 | ||
6b803e5a | 19 | #include "libxfs.h" |
2bd0ea18 NS |
20 | #include "bit.h" |
21 | ||
984af2e1 DW |
22 | int |
23 | getbit_l( | |
2bd0ea18 NS |
24 | char *ptr, |
25 | int bit) | |
26 | { | |
27 | int mask; | |
28 | int shift; | |
29 | ||
30 | ptr += byteize(bit); | |
31 | bit = bitoffs(bit); | |
32 | shift = 7 - bit; | |
33 | mask = 1 << shift; | |
34 | return (*ptr & mask) >> shift; | |
35 | } | |
36 | ||
984af2e1 DW |
37 | void |
38 | setbit_l( | |
2bd0ea18 NS |
39 | char *ptr, |
40 | int bit, | |
41 | int val) | |
42 | { | |
43 | int mask; | |
44 | int shift; | |
45 | ||
46 | ptr += byteize(bit); | |
47 | bit = bitoffs(bit); | |
48 | shift = 7 - bit; | |
49 | mask = (1 << shift); | |
50 | if (val) { | |
51 | *ptr |= mask; | |
52 | } else { | |
53 | mask = ~mask; | |
54 | *ptr &= mask; | |
55 | } | |
56 | } | |
57 | ||
14f8b681 | 58 | int64_t |
2bd0ea18 NS |
59 | getbitval( |
60 | void *obj, | |
61 | int bitoff, | |
62 | int nbits, | |
63 | int flags) | |
64 | { | |
65 | int bit; | |
66 | int i; | |
67 | char *p; | |
14f8b681 | 68 | int64_t rval; |
2bd0ea18 NS |
69 | int signext; |
70 | int z1, z2, z3, z4; | |
dfc130f3 RC |
71 | |
72 | ASSERT(nbits<=64); | |
2bd0ea18 NS |
73 | |
74 | p = (char *)obj + byteize(bitoff); | |
75 | bit = bitoffs(bitoff); | |
76 | signext = (flags & BVSIGNED) != 0; | |
ee6cd73e | 77 | z4 = ((intptr_t)p & 0xf) == 0 && bit == 0; |
5e656dbb BN |
78 | if (nbits == 64 && z4) |
79 | return be64_to_cpu(*(__be64 *)p); | |
ee6cd73e | 80 | z3 = ((intptr_t)p & 0x7) == 0 && bit == 0; |
2bd0ea18 NS |
81 | if (nbits == 32 && z3) { |
82 | if (signext) | |
5e656dbb | 83 | return (__s32)be32_to_cpu(*(__be32 *)p); |
2bd0ea18 | 84 | else |
5e656dbb | 85 | return (__u32)be32_to_cpu(*(__be32 *)p); |
2bd0ea18 | 86 | } |
ee6cd73e | 87 | z2 = ((intptr_t)p & 0x3) == 0 && bit == 0; |
2bd0ea18 NS |
88 | if (nbits == 16 && z2) { |
89 | if (signext) | |
5e656dbb | 90 | return (__s16)be16_to_cpu(*(__be16 *)p); |
2bd0ea18 | 91 | else |
5e656dbb | 92 | return (__u16)be16_to_cpu(*(__be16 *)p); |
2bd0ea18 | 93 | } |
ee6cd73e | 94 | z1 = ((intptr_t)p & 0x1) == 0 && bit == 0; |
2bd0ea18 NS |
95 | if (nbits == 8 && z1) { |
96 | if (signext) | |
5e656dbb | 97 | return *(__s8 *)p; |
2bd0ea18 | 98 | else |
5e656dbb | 99 | return *(__u8 *)p; |
2bd0ea18 | 100 | } |
dfc130f3 RC |
101 | |
102 | ||
2bd0ea18 | 103 | for (i = 0, rval = 0LL; i < nbits; i++) { |
984af2e1 | 104 | if (getbit_l(p, bit + i)) { |
dfc130f3 RC |
105 | /* If the last bit is on and we care about sign |
106 | * bits and we don't have a full 64 bit | |
107 | * container, turn all bits on between the | |
108 | * sign bit and the most sig bit. | |
109 | */ | |
110 | ||
111 | /* handle endian swap here */ | |
2bd0ea18 NS |
112 | #if __BYTE_ORDER == LITTLE_ENDIAN |
113 | if (i == 0 && signext && nbits < 64) | |
114 | rval = -1LL << nbits; | |
115 | rval |= 1LL << (nbits - i - 1); | |
116 | #else | |
117 | if ((i == (nbits - 1)) && signext && nbits < 64) | |
dfc130f3 | 118 | rval |= (-1LL << nbits); |
06ac6550 | 119 | rval |= 1LL << (nbits - i - 1); |
2bd0ea18 NS |
120 | #endif |
121 | } | |
122 | } | |
123 | return rval; | |
124 | } | |
125 | ||
dc151328 MT |
126 | /* |
127 | * The input data can be 8, 16, 32, and 64 sized numeric values | |
128 | * aligned on a byte boundry, or odd sized numbers stored on odd | |
129 | * aligned offset (for example the bmbt fields). | |
130 | * | |
131 | * The input data sent to this routine has been converted to big endian | |
132 | * and has been adjusted in the array so that the first input bit is to | |
133 | * be written in the first bit in the output. | |
134 | * | |
135 | * If the field length and the output buffer are byte aligned, then use | |
136 | * memcpy from the input to the output, but if either entries are not byte | |
137 | * aligned, then loop over the entire bit range reading the input value | |
138 | * and set/clear the matching bit in the output. | |
139 | * | |
140 | * example when ibuf is not multiple of a byte in length: | |
141 | * | |
142 | * ibuf: | BBBBBBBB | bbbxxxxx | | |
143 | * \\\\\\\\--\\\\ | |
144 | * obuf+bitoff: | xBBBBBBB | Bbbbxxxx | | |
145 | * | |
146 | */ | |
2bd0ea18 NS |
147 | void |
148 | setbitval( | |
dc151328 MT |
149 | void *obuf, /* start of buffer to write into */ |
150 | int bitoff, /* bit offset into the output buffer */ | |
151 | int nbits, /* number of bits to write */ | |
152 | void *ibuf) /* source bits */ | |
2bd0ea18 | 153 | { |
dc151328 MT |
154 | char *in = ibuf; |
155 | char *out = obuf; | |
156 | int bit; | |
157 | ||
158 | if (bitoff % NBBY || nbits % NBBY) { | |
159 | for (bit = 0; bit < nbits; bit++) | |
984af2e1 | 160 | setbit_l(out, bit + bitoff, getbit_l(in, bit)); |
dc151328 MT |
161 | } else |
162 | memcpy(out + byteize(bitoff), in, byteize(nbits)); | |
2bd0ea18 | 163 | } |