+static const guint8 bit_mask8[] = {
+ 0xff,
+ 0x7f,
+ 0x3f,
+ 0x1f,
+ 0x0f,
+ 0x07,
+ 0x03,
+ 0x01
+};
+
+/* Bit offset mask for number of bits = 8 - 16 */
+static const guint16 bit_mask16[] = {
+ 0xffff,
+ 0x7fff,
+ 0x3fff,
+ 0x1fff,
+ 0x0fff,
+ 0x07ff,
+ 0x03ff,
+ 0x01ff
+};
+
+/* Get 1 - 8 bits */
+guint8
+tvb_get_bits8(tvbuff_t *tvb, gint bit_offset, const gint no_of_bits)
+{
+ gint offset;
+ guint16 value = 0;
+ guint8 tot_no_bits;
+
+ if (no_of_bits>8) {
+ DISSECTOR_ASSERT_NOT_REACHED();
+ }
+ /* Byte align offset */
+ offset = bit_offset>>3;
+
+ /* Find out which mask to use for the most significant octet
+ * by convering bit_offset into the offset into the first
+ * fetched octet.
+ */
+ bit_offset = bit_offset & 0x7;
+ tot_no_bits = bit_offset+no_of_bits;
+ if(tot_no_bits<=8){
+ /* Read one octet, mask off bit_offset bits and left shift out the unused bits */
+ value = tvb_get_guint8(tvb,offset) & bit_mask8[bit_offset];
+ value = value >> (8-tot_no_bits);
+ }else{
+ /* Read two octets, mask off bit_offset bits and left shift out the unused bits */
+ value = tvb_get_ntohs(tvb,offset) & bit_mask16[bit_offset];
+ value = value >> (16 - tot_no_bits);
+ }
+
+ return (guint8)value;
+}
+
+/* Get 9 - 16 bits */
+/* Bit offset mask for number of bits = 16 - 32 */
+static const guint32 bit_mask32[] = {
+ 0xffffffff,
+ 0x7fffffff,
+ 0x3fffffff,
+ 0x1fffffff,
+ 0x0fffffff,
+ 0x07ffffff,
+ 0x03ffffff,
+ 0x01ffffff
+};
+
+guint16
+tvb_get_bits16(tvbuff_t *tvb, gint bit_offset, const gint no_of_bits,const gboolean little_endian)
+{
+ gint offset;
+ guint16 value = 0;
+ guint16 tempval = 0;
+ guint8 tot_no_bits;
+
+ if ((no_of_bits<=8)||(no_of_bits>16)) {
+ /* If bits <= 8 use tvb_get_bits8 */
+ DISSECTOR_ASSERT_NOT_REACHED();
+ }
+ if(little_endian){
+ DISSECTOR_ASSERT_NOT_REACHED();
+ /* This part is not implemented yet */
+ }
+
+ /* Byte align offset */
+ offset = bit_offset>>3;
+
+ /* Find out which mask to use for the most significant octet
+ * by convering bit_offset into the offset into the first
+ * fetched octet.
+ */
+ bit_offset = bit_offset & 0x7;
+ tot_no_bits = bit_offset+no_of_bits;
+ /* Read two octets and mask off bit_offset bits */
+ value = tvb_get_ntohs(tvb,offset) & bit_mask16[bit_offset];
+ if(tot_no_bits < 16){
+ /* Left shift out the unused bits */
+ value = value >> (16 - tot_no_bits);
+ }else if(tot_no_bits > 16){
+ /* Spans three octets, read next octet and shift as needed */
+ value = value << (tot_no_bits - 16);
+ tempval = tvb_get_guint8(tvb,offset+2);
+ tempval = tempval >> (24-tot_no_bits);
+ value = value | tempval;
+ }
+
+ return value;
+}
+
+/* Bit offset mask for number of bits = 32 - 64 */
+static const guint64 bit_mask64[] = {
+ G_GINT64_CONSTANT(0xffffffffffffffffU),
+ G_GINT64_CONSTANT(0x7fffffffffffffffU),
+ G_GINT64_CONSTANT(0x3fffffffffffffffU),
+ G_GINT64_CONSTANT(0x1fffffffffffffffU),
+ G_GINT64_CONSTANT(0x0fffffffffffffffU),
+ G_GINT64_CONSTANT(0x07ffffffffffffffU),
+ G_GINT64_CONSTANT(0x03ffffffffffffffU),
+ G_GINT64_CONSTANT(0x01ffffffffffffffU)
+};
+
+guint32
+tvb_get_bits32(tvbuff_t *tvb, gint bit_offset, const gint no_of_bits, const gboolean little_endian)
+{
+ gint offset;
+ guint32 value = 0;
+ guint32 tempval = 0;
+ guint8 tot_no_bits;
+ guint8 tot_no_octets = 0;
+ guint8 i = 0;
+ gint8 shift = 0;
+
+ if ((no_of_bits<=16)||(no_of_bits>32)) {
+ /* If bits <= 16 use tvb_get_bits8 or tvb_get_bits16 */
+ DISSECTOR_ASSERT_NOT_REACHED();
+ }
+ if(little_endian){
+ DISSECTOR_ASSERT_NOT_REACHED();
+ /* This part is not implemented yet */
+ }
+
+ /* Byte align offset */
+ offset = bit_offset>>3;
+
+ bit_offset = bit_offset & 0x7;
+ tot_no_bits = bit_offset+no_of_bits;
+ tot_no_octets = tot_no_bits / 8;
+ if (tot_no_bits % 8)
+ tot_no_octets++;
+ shift = no_of_bits - (8 - bit_offset);
+
+ value = tvb_get_guint8(tvb, offset) & bit_mask8[bit_offset];
+ value = value << shift;
+
+ for (i = 1; i < tot_no_octets; i++)
+ {
+ shift = shift - 8;
+ tempval = tvb_get_guint8(tvb, offset+i);
+ if (shift >= 0)
+ {
+ tempval = tempval << shift;
+ }
+ else
+ {
+ tempval = tempval >> (8 - shift);
+ }
+ value = value | tempval;
+ }
+
+ return value;
+}
+
+guint64
+tvb_get_bits64(tvbuff_t *tvb, gint bit_offset, const gint no_of_bits, const gboolean little_endian)
+{
+ gint offset;
+ guint64 value = 0;
+ guint64 tempval = 0;
+ guint8 tot_no_bits;
+
+ if ((no_of_bits<=32)||(no_of_bits>64)) {
+ /* If bits <= 32 use tvb_get_bits8, tvb_get_bits16 or tvb_get_bits32 */
+ DISSECTOR_ASSERT_NOT_REACHED();
+ }
+ if(little_endian){
+ DISSECTOR_ASSERT_NOT_REACHED();
+ /* This part is not implemented yet */
+ }
+
+ /* Byte align offset */
+ offset = bit_offset>>3;
+
+ /* Find out which mask to use for the most significant octet
+ * by convering bit_offset into the offset into the first
+ * fetched octet.
+ */
+ bit_offset = bit_offset & 0x7;
+ tot_no_bits = bit_offset+no_of_bits;
+ /* Read eight octets and mask off bit_offset bits */
+ value = tvb_get_ntoh64(tvb,offset) & bit_mask64[bit_offset];
+ if (tot_no_bits < 64){
+ /* Left shift out the unused bits */
+ value = value >> (64 - tot_no_bits);
+ }else if (tot_no_bits > 64){
+ /* Spans nine octets, read next octet and shift as needed */
+ value = value << (tot_no_bits - 64);
+ tempval = tvb_get_guint8(tvb,offset+8);
+ tempval = tempval >> (72-tot_no_bits);
+ value = value | tempval;
+ }
+
+ return value;
+}
+
+guint32
+tvb_get_bits(tvbuff_t *tvb, const gint bit_offset, const gint no_of_bits, const gboolean little_endian)
+{
+ /* This function can handle only up to 32 requested bits */
+ if (no_of_bits > 32)
+ DISSECTOR_ASSERT_NOT_REACHED();
+
+ if (no_of_bits == 0)
+ return 0;
+
+ /* Number of requested bits is in range [17, 32] */
+ if (no_of_bits > 16)
+ return tvb_get_bits32(tvb, bit_offset, no_of_bits, little_endian);
+
+ /* Number of requested bits is in range [9, 16] */
+ if (no_of_bits > 8)
+ return tvb_get_bits16(tvb, bit_offset, no_of_bits, little_endian);
+
+ /* Number of requested bits is in range [1, 8] */
+ return tvb_get_bits8(tvb, bit_offset, no_of_bits);
+}
+