summaryrefslogtreecommitdiff
path: root/cesar/lib/bitstream.h
blob: 8ee8ff098277e84ad79fdd728b916599459d0e99 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
#ifndef bitstream_h
#define bitstream_h
/* Cesar project {{{
 *
 * Copyright (C) 2007 Spidcom
 *
 * <<<Licence>>>
 *
 * }}} */
/**
 * \file    bitstream.h
 * \brief   Bit stream access using word access.
 * \ingroup lib
 *
 * This library provides sequential bit stream access functions using word
 * access, providing bus optimised endian and boundary safe access.
 */

#define bitsizeof(x) (8*sizeof(x))

/** Forward declaration. */
typedef struct bitstream_t bitstream_t;

/** Function callback to call when the buffer is full.
 * \param  ctx  the bitstream context.
 * \param  user_data  the user data.
 */
typedef void (*bitstream_buffer_cb_t) (bitstream_t *ctx, void *user_data);

typedef enum
{
    BITSTREAM_READ,
    BITSTREAM_WRITE
} bitstream_type_t;

/** Bit stream sequential read context. */
struct bitstream_t
{
    /** Beginning address of data structure. */
    u8 *start;
    /** Bit stream pointer, read as words. */
    u32 *stream;
    /** Number of valid bytes in the stream. */
    uint nb_bytes;
    /** Bit offset of current read or write word. */
    uint bit_offset;
    /** Input buffer, valid bits are in LSB. */
    u32 buf;
    /** Bitstream type of access (Read or Write). */
    bitstream_type_t type;
    /** Function to call when the buffer is full. */
    bitstream_buffer_cb_t buffer_cb;
    /** Function user data to provide when the buffer is full. */
    void *user_data;
    /** Boolean to indicate if the buffer callback is setted or not. */
    bool buffer_cb_present;
};



/**
 * Initialise a bit stream.
 * \param  ctx  bit stream context
 * \param  data  stream data pointer
 * \param  nb_bytes  number of valid bytes in the stream
 *
 * Memory pointer doesn't have to be word aligned.
 */
void
bitstream_init (bitstream_t *ctx, void *data, uint nb_bytes,
                bitstream_type_t type);

/**
 * Write remaining bits.
 * \param  ctx  bit stream context
 * \return  number of written bits if access is write, else 0
 */
uint
bitstream_finalise (bitstream_t *ctx);

/**
 * Initialise the function to call when the buffer is full.
 * \param  ctx  the bitstream context.
 * \param  cb  the function callback.
 * \param  user_data  the user data.
 */
void
bitstream_buffer_full_init_cb (bitstream_t *ctx, bitstream_buffer_cb_t cb,
                               void *user_data);

uint bitstream_access_unknown_size (void);

/**
 * Read or write bits from the bit stream.
 * \param  ctx  bit stream context
 * \param  value
 * \param  nb_bit  number of bits to read (1-64)
 * \return  number of bits read/written
 *
 * Access type (read or write) depends on context initialization.
 */
#define bitstream_access(ctx, value, nb_bit)                                  \
      (sizeof(*(value)) == 1 ? bitstream_access_8 ((ctx), (void *) (value), (nb_bit))  \
    : (sizeof(*(value)) == 2 ? bitstream_access_16 ((ctx), (void *) (value), (nb_bit)) \
    : (sizeof(*(value)) == 4 ? bitstream_access_32 ((ctx), (void *) (value), (nb_bit)) \
    : (sizeof(*(value)) == 8 ? bitstream_access_64 ((ctx), (void *) (value), (nb_bit)) \
    : bitstream_access_unknown_size ()))))

/**
 * Read shortcut to avoid temporary variable.
 * \param  ctx  bit stream context
 * \param  nb_bit  number of bits to read
 * \return  value read
 *
 * \warning nb_bit max is 32.
 */
#define bitstream_read(ctx, nb_bit) \
    ({ \
        u32 _value; \
        bitstream_access ((ctx), &_value, (nb_bit)); \
        _value; \
    })

/**
 * Write shortcut to avoid temporary variable.
 * \param  ctx  bit stream context
 * \param  value  value to write
 * \param  nb_bit  number of bits to write
 */
#define bitstream_write(ctx, value, nb_bit) \
    do { \
        typeof (value) _value = (value); \
        bitstream_access ((ctx), &_value, (nb_bit)); \
    } while (0)

/**
 * Return the number of remaining bits before the read or write limit.
 * \param  ctx  bit stream context
 * \return  number of remaining bits
 *
 * Using this function, the user can check whether the next read or
 * write accesses will succeed.
 */
uint
bitstream_available_bits (bitstream_t *ctx);

/**
 * Return the number of bytes processed from the start of the bitstream.
 * \param  ctx  the bit stream context.
 * \return  the number of bytes processed.
 *
 * Compute the number of bytes processed from the start of the stream to the
 * current position of the stream.
 */
uint
bitstream_bytes_processed (bitstream_t *ctx);

/**
 * Read or write the next "nb_bit" from/to the memory pointer
 * stored into the ctx.
 * \param  ctx  bit stream context
 * \param  value  pointer to the value
 * \param nb_bit  number of bits to read
 *
 * Access type (read or write) depends on context initialization.
 */
uint
bitstream_access_8 (bitstream_t *ctx, void *value, uint nb_bit);

/**
 * Read or write the next "nb_bit" from/to the memory pointer
 * stored into the ctx.
 * \param  ctx  bit stream context
 * \param  value  pointer to the value
 * \param nb_bit  number of bits to read
 *
 * Access type (read or write) depends on context initialization.
 */
uint
bitstream_access_16 (bitstream_t *ctx, void *value, uint nb_bit);

/**
 * Read or write the next "nb_bit" from/to the memory pointer
 * stored into the ctx.
 * \param  ctx  bit stream context
 * \param  value  pointer to the value
 * \param nb_bit  number of bits to read
 *
 * Access type (read or write) depends on context initialization.
 */
uint
bitstream_access_32 (bitstream_t *ctx, void *value, uint nb_bit);

/**
 * Read or write the next "nb_bit" from/to the memory pointer
 * stored into the ctx.
 * \param  ctx  bit stream context
 * \param  value  pointer to the value
 * \param nb_bit  number of bits to read
 *
 * Access type (read or write) depends on context initialization.
 */
uint
bitstream_access_64 (bitstream_t *ctx, void *value, uint nb_bit);

/**
 * Read or write "len" bytes from/to the bitstream
 * \param ctx bitstream context
 * \param buf buffer to read from or write to
 * \param len buffer length in bytes
 */
void
bitstream_access_buf (bitstream_t *ctx, void *buf, size_t len);

/**
 * Read or write maximum of len characters from/to a bitstream
 * \param ctx bitstream context
 * \param buf the buffer to read from or write to
 * \param len maximum string length in bytes
 */
size_t
bitstream_access_str (bitstream_t *ctx, char *buf, size_t len);

/**
 * Read "nb_bit" bits from data pointer + bit offset
 * \param  data  data base pointer
 * \param  bit_offset  bit offset
 * \param  nb_bit  number of bits to read
 * \return  bit read data
 *
 * Bit number must be <= 32 or use bitstream_direct_read_large
 */
uint
bitstream_direct_read (void *data, uint bit_offset, uint nb_bit);

/**
 * Read "nb_bit" bits from data pointer + bit offset
 * \param  data  data base pointer
 * \param  bit_offset  bit offset
 * \param  nb_bit  number of bits to read
 * \return  bit read data
 */
u64
bitstream_direct_read_large (u8 *data, uint bit_offset, uint nb_bit);

/**
 * Write "nb_bit" bits to data pointer + bit offset
 * \param  data  data base pointer
 * \param  bit_offset  bit offset
 * \param  value  bit value to write
 * \param  nb_bit  number of bits to write
 *
 * Bit number must be <= 32 or use bitstream_direct_write_large
 */
void
bitstream_direct_write (void *data, uint bit_offset, uint value, uint nb_bit);

/**
 * Write "nb_bit" bits to data pointer + bit offset
 * \param  data  data base pointer
 * \param  bit_offset  bit offset
 * \param  value  bit value to write
 * \param  nb_bit  number of bits to write
*/
void
bitstream_direct_write_large (u8 *data, uint bit_offset, u64 value,
                              uint nb_bit);

/* *** /!\ DEPRECATED *** */

/**
 * DEPRECATED. Similar to memcpy from the std libc
 * Use bitstream_access_buf instead.
 */
void*
bitstream_memcpy (void *dest, void *src, size_t len);

/**
 * DEPRECATED. Compare two buffers and return true if the buffers are equals.
 * \param  s1  the first buffer to compare.
 * \param  s2  the second buffer to compare.
 * \param  len  the length in bytes to compare the buffers.
 * \return  true if equal, false otherwise.
 */
bool
bitstream_memcmp (void *s1, void *s2, size_t len);

/**
 * DEPRECATED. Similar to the strncpy from the standard libc.
 * Use bistream_access_str instead.
 * \param ctx The bitstream context (BITSTREAM_READ mode only)
 * \param dest The destination string
 * \param n The maximum length of the string
 */
char*
bitstream_strncpy (bitstream_t *ctx, char *dest, size_t n);

#endif /* bitstream_h */