aboutsummaryrefslogtreecommitdiffstats
path: root/epan/tvbuff.c
diff options
context:
space:
mode:
Diffstat (limited to 'epan/tvbuff.c')
-rw-r--r--epan/tvbuff.c185
1 files changed, 169 insertions, 16 deletions
diff --git a/epan/tvbuff.c b/epan/tvbuff.c
index c44bca3338..24fbd167c9 100644
--- a/epan/tvbuff.c
+++ b/epan/tvbuff.c
@@ -56,6 +56,9 @@
static guint64
_tvb_get_bits64(tvbuff_t *tvb, guint bit_offset, const gint total_no_of_bits);
+static guint64
+_tvb_get_bits64_le(tvbuff_t *tvb, guint bit_offset, const gint total_no_of_bits);
+
static inline gint
_tvb_captured_length_remaining(const tvbuff_t *tvb, const gint offset);
@@ -434,6 +437,72 @@ tvb_new_octet_aligned(tvbuff_t *tvb, guint32 bit_offset, gint32 no_of_bits)
return sub_tvb;
}
+tvbuff_t *
+tvb_new_octet_right_aligned(tvbuff_t *tvb, guint32 bit_offset, gint32 no_of_bits)
+{
+ tvbuff_t *sub_tvb = NULL;
+ guint32 byte_offset;
+ gint src_len, dst_len, i;
+ guint8 left, right, remaining_bits, *buf;
+ const guint8 *data;
+
+ DISSECTOR_ASSERT(tvb && tvb->initialized);
+
+ byte_offset = bit_offset / 8;
+ /* right shift to put bits in place and discard least significant bits */
+ right = bit_offset % 8;
+ /* left shift to get most significant bits from next octet */
+ left = 8 - right;
+
+ if (no_of_bits == -1) {
+ dst_len = _tvb_captured_length_remaining(tvb, byte_offset);
+ remaining_bits = 0;
+ } else {
+ dst_len = no_of_bits / 8;
+ remaining_bits = no_of_bits % 8;
+ if (remaining_bits) {
+ dst_len++;
+ }
+ }
+
+ /* already aligned -> shortcut */
+ if ((right == 0) && (remaining_bits == 0)) {
+ return tvb_new_subset_length_caplen(tvb, byte_offset, dst_len, dst_len);
+ }
+
+ DISSECTOR_ASSERT(dst_len>0);
+
+ if (_tvb_captured_length_remaining(tvb, byte_offset) > dst_len) {
+ /* last octet will get data from trailing octet */
+ src_len = dst_len + 1;
+ } else {
+ /* last octet will be zero padded */
+ src_len = dst_len;
+ }
+
+ data = ensure_contiguous(tvb, byte_offset, src_len); /* tvb_get_ptr */
+
+ /* Do this allocation AFTER tvb_get_ptr() (which could throw an exception) */
+ buf = (guint8 *)g_malloc(dst_len);
+
+ for (i = 0; i < (dst_len - 1); i++)
+ buf[i] = (data[i] >> right) | (data[i+1] << left);
+
+ /* Special handling for last octet */
+ buf[i] = (data[i] >> right);
+ /* Shift most significant bits from trailing octet if available */
+ if (src_len > dst_len)
+ buf[i] |= (data[i+1] << left);
+ /* Preserve only remaining bits in last octet if not multiple of 8 */
+ if (remaining_bits)
+ buf[i] &= ((1 << remaining_bits) - 1);
+
+ sub_tvb = tvb_new_child_real_data(tvb, buf, dst_len, dst_len);
+ tvb_set_free_cb(sub_tvb, g_free);
+
+ return sub_tvb;
+}
+
static tvbuff_t *
tvb_generic_clone_offset_len(tvbuff_t *tvb, guint offset, guint len)
{
@@ -2007,12 +2076,20 @@ static const guint8 bit_mask8[] = {
/* Get a variable ammount of bits
*
- * Return a byte array with bit limited data. The data is aligned to the right.
+ * Return a byte array with bit limited data.
+ * When encoding is ENC_BIG_ENDIAN, the data is aligned to the left.
+ * When encoding is ENC_LITTLE_ENDIAN, the data is aligned to the right.
*/
guint8 *
-tvb_get_bits_array(wmem_allocator_t *scope, tvbuff_t *tvb, const gint bit_offset, size_t no_of_bits, size_t *data_length)
+tvb_get_bits_array(wmem_allocator_t *scope, tvbuff_t *tvb, const gint bit_offset,
+ size_t no_of_bits, size_t *data_length, const guint encoding)
{
- tvbuff_t *sub_tvb = tvb_new_octet_aligned(tvb, bit_offset, (gint32) no_of_bits);
+ tvbuff_t *sub_tvb;
+ if (encoding & ENC_LITTLE_ENDIAN) {
+ sub_tvb = tvb_new_octet_right_aligned(tvb, bit_offset, (gint32) no_of_bits);
+ } else {
+ sub_tvb = tvb_new_octet_aligned(tvb, bit_offset, (gint32) no_of_bits);
+ }
*data_length = tvb_reported_length(sub_tvb);
return (guint8*)tvb_memdup(scope, sub_tvb, 0, *data_length);
}
@@ -2024,33 +2101,37 @@ tvb_get_bits8(tvbuff_t *tvb, guint bit_offset, const gint no_of_bits)
return (guint8)_tvb_get_bits64(tvb, bit_offset, no_of_bits);
}
-/* Get 9 - 16 bits */
+/* Get 1 - 16 bits */
guint16
-tvb_get_bits16(tvbuff_t *tvb, guint bit_offset, const gint no_of_bits,const guint encoding _U_)
+tvb_get_bits16(tvbuff_t *tvb, guint bit_offset, const gint no_of_bits, const guint encoding)
{
- /* note that encoding has no meaning here, as the tvb is considered to contain an octet array */
- return (guint16)_tvb_get_bits64(tvb, bit_offset, no_of_bits);
+ return (guint16)tvb_get_bits64(tvb, bit_offset, no_of_bits, encoding);
}
/* Get 1 - 32 bits */
guint32
-tvb_get_bits32(tvbuff_t *tvb, guint bit_offset, const gint no_of_bits, const guint encoding _U_)
+tvb_get_bits32(tvbuff_t *tvb, guint bit_offset, const gint no_of_bits, const guint encoding)
{
- /* note that encoding has no meaning here, as the tvb is considered to contain an octet array */
- return (guint32)_tvb_get_bits64(tvb, bit_offset, no_of_bits);
+ return (guint32)tvb_get_bits64(tvb, bit_offset, no_of_bits, encoding);
}
/* Get 1 - 64 bits */
guint64
-tvb_get_bits64(tvbuff_t *tvb, guint bit_offset, const gint no_of_bits, const guint encoding _U_)
+tvb_get_bits64(tvbuff_t *tvb, guint bit_offset, const gint no_of_bits, const guint encoding)
{
- /* note that encoding has no meaning here, as the tvb is considered to contain an octet array */
- return _tvb_get_bits64(tvb, bit_offset, no_of_bits);
+ /* encoding determines bit numbering within octet array */
+ if (encoding & ENC_LITTLE_ENDIAN) {
+ return _tvb_get_bits64_le(tvb, bit_offset, no_of_bits);
+ } else {
+ return _tvb_get_bits64(tvb, bit_offset, no_of_bits);
+ }
}
+
/*
* This function will dissect a sequence of bits that does not need to be byte aligned; the bits
* set will be shown in the tree as ..10 10.. and the integer value returned if return_value is set.
* Offset should be given in bits from the start of the tvb.
+ * Bits within octet are numbered from MSB (0) to LSB (7). Bit at bit_offset is return value most significant bit.
* The function tolerates requests for more than 64 bits, but will only return the least significant 64 bits.
*/
static guint64
@@ -2126,12 +2207,84 @@ _tvb_get_bits64(tvbuff_t *tvb, guint bit_offset, const gint total_no_of_bits)
}
return value;
}
+
+/*
+ * Offset should be given in bits from the start of the tvb.
+ * Bits within octet are numbered from LSB (0) to MSB (7). Bit at bit_offset is return value least significant bit.
+ * The function tolerates requests for more than 64 bits, but will only return the least significant 64 bits.
+ */
+static guint64
+_tvb_get_bits64_le(tvbuff_t *tvb, guint bit_offset, const gint total_no_of_bits)
+{
+ guint64 value = 0;
+ guint octet_offset = bit_offset / 8;
+ gint remaining_bits = total_no_of_bits;
+ gint shift = 0;
+
+ if (remaining_bits > 64)
+ {
+ remaining_bits = 64;
+ }
+
+ if (bit_offset % 8)
+ {
+ /* not aligned, extract bits from first octet */
+ shift = 8 - (bit_offset % 8);
+ value = tvb_get_guint8(tvb, octet_offset) >> (bit_offset % 8);
+ if (shift > total_no_of_bits)
+ {
+ /* keep only the requested bits */
+ value &= (G_GUINT64_CONSTANT(1) << total_no_of_bits) - 1;
+ remaining_bits = 0;
+ }
+ else
+ {
+ remaining_bits = total_no_of_bits - shift;
+ }
+ octet_offset++;
+ }
+
+ while (remaining_bits > 0)
+ {
+ /* take the biggest words, shorts or octets that we can */
+ if (remaining_bits >= 32)
+ {
+ value |= ((guint64)tvb_get_letohl(tvb, octet_offset) << shift);
+ shift += 32;
+ remaining_bits -= 32;
+ octet_offset += 4;
+ }
+ else if (remaining_bits >= 16)
+ {
+ value |= ((guint64)tvb_get_letohs(tvb, octet_offset) << shift);
+ shift += 16;
+ remaining_bits -= 16;
+ octet_offset += 2;
+ }
+ else if (remaining_bits >= 8)
+ {
+ value |= ((guint64)tvb_get_guint8(tvb, octet_offset) << shift);
+ shift += 8;
+ remaining_bits -= 8;
+ octet_offset += 1;
+ }
+ else
+ {
+ guint mask = (1 << remaining_bits) - 1;
+ value |= (((guint64)tvb_get_guint8(tvb, octet_offset) & mask) << shift);
+ shift += remaining_bits;
+ remaining_bits = 0;
+ octet_offset += 1;
+ }
+ }
+ return value;
+}
+
/* Get 1 - 32 bits (should be deprecated as same as tvb_get_bits32??) */
guint32
-tvb_get_bits(tvbuff_t *tvb, const guint bit_offset, const gint no_of_bits, const guint encoding _U_)
+tvb_get_bits(tvbuff_t *tvb, const guint bit_offset, const gint no_of_bits, const guint encoding)
{
- /* note that encoding has no meaning here, as the tvb is considered to contain an octet array */
- return (guint32)_tvb_get_bits64(tvb, bit_offset, no_of_bits);
+ return (guint32)tvb_get_bits64(tvb, bit_offset, no_of_bits, encoding);
}
static gint