Newbie question: How to define a class that will work on bits from abinary file?

D

Damfino

Hi all,
Newbie question here wrt defining a class that will work on bits read
from a binary file. How would you go about doing it? As an example
please look at the structure of my data given below. The data comes in
40 byte packets via stdin or a binary file.
my_Data_pkt(){
syncByte (8bits)
XML_type (2bits)
XML_subtype (2bits)
record_value (3bits)
playout_flag (1bit)
if (playout_flag=='1') {
playout_length (8bits)
for (i=0; i< playout_length; i++){
playout_data
}
}
payload to fill the rest of the 40 bytes
}
How would this be defined as a class?
How would you retrieve the values for the different variables within
the packet?
How would you set the variables to a specific value?

Any help would be appreciated.

Regards
 
M

Michael DOUBEZ

Victor Bazarov a écrit :
// assuming that 'char' is 8 bits


And assuming the machine is in little endian. In big endian, you would
have to invert the bit fields.
class DataPacket {
// somehow control the alignment and make it 1 byte
// to avoid padding between members of this class
char syncByte; // not sure you need this to be kept
struct BitStuff {
unsigned XML_type:2;
unsigned XML_subtype:2;
unsigned record_value:3;
unsigned payout:1;
} fields;
char restOfPacket[38];
public:
// member functions go here
};

Why do you use an intermediary structure, I would have simply defined
(without LSB/MSB logic):
struct XML_Data
{
char syncByte;//8 bits
unsigned char XML_type:2; // 2 bits
unsigned char XML_subtype:2; //+2 bits
unsigned char record_value:3; //+3 bits
unsigned char payout:1; //+1 bits = 8 bits => aligned
char restOfPacket[38];
};

Michael
 
J

James Kanze

Victor Bazarov a écrit :
And assuming the machine is in little endian. In big endian,
you would have to invert the bit fields.

Or maybe it wouldn't work at all. How the compiler lays out bit
fields is implementation dependent, and varies greatly. Bit
fields cannot be used for mapping external data formats.

It's possible to write a stream which reads arbitrary bit
lengths; I did it once in the past (for use with a compression
algorithm). It's rarely necessary, however, since in practice,
files aren't defined as streams of bits, but as streams of
bytes. So his actual file format is probably something more
like:

+---+---+---+---+---+---+---+---+
byte 1 | sync |
+---+---+---+---+---+---+---+---+
+---+---+---+---+---+---+---+---+
byte 2 | type |subtype| rec. value| F |
+---+---+---+---+---+---+---+---+

...

He streams in bytes (as unsigned char), and processes them one
after the other.

Internally, it's up to him (and his design) whether he maintains
the information in byte 2 in separate variables, or in a single
unsigned char, extracting the individual fields on an as needed
basis. At any rate, the functions to get the field from the
byte would look something like:

XMLTypeId
getType( unsigned char byte2 )
{
return static_cast< XMLTypeId >( (byte2 >> 6) & 0x03 ) ;
}

(except, of course, that one would use named constants instead
of the magic numbers). Depending on the application, he might
be able to define XMLTypeId as something like:

enum XMLTypeId
{
type1 = 0x00,
type2 = 0x40,
type3 = 0x80,
type4 = 0xC0,
typeMask = type1 | type2 | type3 | type 4
} ;

and skip the shift, i.e.:

XMLTypeId
getType( unsigned char byte2 )
{
return static_cast< XMLTypeId >( byte2 & typeMask ) ;
}

There's no portable way to use bit fields to map to an external
representation. (You could use bit fields for the internal
representation, in order to save memory.)

And one last point, while I'm at it. In the original posting,
it was mentionned that he might be reading from standard in.
There is no way to read binary data from std::cin (nor from
stdin in C).
 
N

Nick Keighley

Or maybe it wouldn't work at all.  How the compiler lays out bit
fields is implementation dependent, and varies greatly.  Bit
fields cannot be used for mapping external data formats.
yes

It's possible to write a stream which reads arbitrary bit
lengths;

I was part way though trying to implement something like
this.

To the OP:
I assumed the data had already been loaded into an array
(or std::vector) of Bytes (unsigned chars). And the class
operated on the blocks of data.

Something like:

typedef std::vector<Byte> Packet;

class BitStream
{
public:
BitStream (Packet&);

// assumes n <= 8
void getBits (const Byte&, int n) const;
void putBits (Byte&, int n);

// used when n > 8
void getBits (const Packet&, int n) const;
void putBits (Packet&, int n);

private:
Packet byte_stream_;
size_t byte_index_;
size_t bit_index_;
};

then's theres a lot of shifts and "ands" and "ors"
I did it once in the past (for use with a compression
algorithm).  It's rarely necessary, however, since in practice,
files aren't defined as streams of bits, but as streams of
bytes.  

ah. If only this were so... There are still bit
oriented protocols out there. Not all the world is
TCP/IP.

So his actual file format is probably something more
like:

               +---+---+---+---+---+---+---+---+
    byte 1     |              sync             |
               +---+---+---+---+---+---+---+---+
               +---+---+---+---+---+---+---+---+
    byte 2     | type  |subtype| rec. value| F |
               +---+---+---+---+---+---+---+---+

     ...

He streams in bytes (as unsigned char), and processes them one
after the other.

<snip>
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
474,174
Messages
2,570,940
Members
47,484
Latest member
JackRichard

Latest Threads

Top