bitpack 0.1

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG ADDED
@@ -0,0 +1,7 @@
1
+ = BitPack Changelog
2
+
3
+ == Version 0.1
4
+
5
+ === November 14, 2007
6
+
7
+ * Initial release.
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2007 Corey Burrows
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README ADDED
@@ -0,0 +1,98 @@
1
+ = BitPack: Library for packing and unpacking binary strings
2
+
3
+ BitPack is a library that provides an easy to use API for packing and
4
+ unpacking arbitrary binary strings. Unlike Array#pack and String#unpack,
5
+ BitPack objects allow you to pack and unpack fields of arbitrary bit lengths.
6
+
7
+ = Installing BitPack
8
+
9
+ Get BitPack from RubyForge.
10
+
11
+ $ gem install bitpack
12
+
13
+ = Example
14
+
15
+ In this example, we will see how to pack and unpack a contrived message format.
16
+
17
+ The format is as follows:
18
+
19
+ * field +foo+: unsigned integer, 3 bits in length
20
+ * field +bar+: unsigned integer, 13 bits in length
21
+ * field +baz+: octet string, +bar+ bytes in length
22
+
23
+
24
+ require 'rubygems'
25
+ require 'bitpack'
26
+
27
+ class Message
28
+ attr_accessor :foo, :bar, :baz
29
+ def initialize(foo=nil, bar=nil, baz=nil)
30
+ @foo = foo
31
+ @bar = bar
32
+ @baz = baz
33
+ end
34
+
35
+ def pack
36
+ # create a new BitPack object to pack the message into
37
+ bp = BitPack.new
38
+
39
+ # pack field foo into 3 bits
40
+ bp.append_bits(@foo, 3)
41
+
42
+ # pack field bar into 13 bits
43
+ bp.append_bits(@bar, 13)
44
+
45
+ # finally, pack baz as a string
46
+ bp.append_bytes(@baz)
47
+
48
+ # convert the BitPack to a string
49
+ bp.to_bytes
50
+ end
51
+
52
+ def self.unpack(bytes)
53
+ m = self.new
54
+
55
+ # create a new BitPack from the packed message string
56
+ bp = BitPack.from_bytes(bytes)
57
+
58
+ # unpack field foo from the first 3 bits
59
+ m.foo = bp.read_bits(3)
60
+
61
+ # unpack field bar from the next 13 bits
62
+ m.bar = bp.read_bits(13)
63
+
64
+ # finally, unpack the string baz from the next bar bytes
65
+ m.baz = bp.read_bytes(m.bar)
66
+
67
+ m
68
+ end
69
+ end
70
+
71
+ m1 = Message.new
72
+ m1.foo = 5
73
+ s = "BitPack makes packing and unpacking binary strings easy!"
74
+ m1.bar = s.length
75
+ m1.baz = s
76
+
77
+ bytes = m1.pack
78
+
79
+ p bytes
80
+ #=> "\2408BitPack makes packing and unpacking binary strings easy!"
81
+
82
+ m2 = Message.unpack(bytes)
83
+ p m2.foo
84
+ #=> 5
85
+ p m2.bar
86
+ #=> 56
87
+ p m2.baz
88
+ #=> "BitPack makes packing and unpacking binary strings easy!"
89
+
90
+
91
+ = Notes
92
+
93
+ BitPack is almost entirely implemented as a C library. If you would like to
94
+ use BitPack from a C program, just grab the bitpack.c and bitpack.h files from
95
+ the ext/ directory of the gem and include them in your project. Documentation
96
+ can be found in bitpack.h and example usage can be seen in test/bitpack_tests.c.
97
+
98
+
data/Rakefile ADDED
@@ -0,0 +1,87 @@
1
+
2
+ require 'rubygems'
3
+ Gem::manage_gems
4
+ require 'rake/gempackagetask'
5
+ require 'rake/clean'
6
+ require 'rake/rdoctask'
7
+
8
+ NAME = 'bitpack'
9
+ VERS = '0.1'
10
+ GEM_NAME = "#{NAME}-#{VERS}.gem"
11
+
12
+ RDOC_MAIN = "README"
13
+
14
+ spec = Gem::Specification.new do |s|
15
+ s.name = NAME
16
+ s.version = VERS
17
+ s.author = "Corey Burrows"
18
+ s.email = "corey.burrows@gmail.com"
19
+ s.platform = Gem::Platform::RUBY
20
+ s.summary = "Library for packing and unpacking binary strings."
21
+ s.files = %w{README CHANGELOG LICENSE Rakefile} +
22
+ Dir.glob("ext/**/*.{h,c,rb}") +
23
+ Dir.glob("lib/**/*.{rb}") +
24
+ Dir.glob("test/**/*.rb")
25
+ s.require_path = "."
26
+ s.autorequire = "bitpack"
27
+ s.extensions = ["ext/extconf.rb"]
28
+ #s.test_file = ""
29
+ s.has_rdoc = true
30
+ s.extra_rdoc_files = [ RDOC_MAIN, "CHANGELOG", "LICENSE" ]
31
+ end
32
+
33
+ Rake::GemPackageTask.new(spec) do |pkg|
34
+ pkg.need_tar = true
35
+ end
36
+
37
+ Rake::RDocTask.new do |rd|
38
+ rd.main = RDOC_MAIN
39
+ rd.rdoc_files.include(RDOC_MAIN, "CHANGELOG", "LICENSE", "ext/**/*.c", "lib/**/*.rb")
40
+ rd.options << "--all"
41
+ end
42
+
43
+ CLEAN.include FileList["ext/**/*.o",
44
+ "ext/**/*.so",
45
+ "ext/**/*.bundle",
46
+ "ext/**/Makefile",
47
+ "ext/**/mkmf.log",
48
+ "pkg/*.gem",
49
+ "test/*.o",
50
+ "test/test_driver",
51
+ "html"
52
+ ]
53
+
54
+ task :build do
55
+ Dir.chdir('ext')
56
+ sh('ruby extconf.rb')
57
+ sh('make')
58
+ Dir.chdir('..')
59
+ end
60
+
61
+ task :c_test do
62
+ Dir.chdir('test')
63
+ sh('make')
64
+ Dir.chdir('..')
65
+ end
66
+
67
+ task :ruby_test do
68
+ Dir.chdir('test')
69
+ sh('ruby bitpack_tests.rb')
70
+ Dir.chdir('..')
71
+ end
72
+
73
+ task :test => [ :build, :c_test, :ruby_test ] do
74
+ end
75
+
76
+ task :gem do
77
+ sh %{rake pkg/#{GEM_NAME}}
78
+ end
79
+
80
+ task :install => :gem do
81
+ sh %{sudo gem install pkg/#{GEM_NAME}}
82
+ end
83
+
84
+ task :uninstall do
85
+ sh %{sudo gem uninstall #{NAME}}
86
+ end
87
+
data/ext/bitpack.c ADDED
@@ -0,0 +1,483 @@
1
+ #include <math.h>
2
+ #include <stdio.h>
3
+ #include <stdlib.h>
4
+ #include <string.h>
5
+
6
+ #include "bitpack.h"
7
+
8
+ /* round up to the nearest multiple of 8 */
9
+ static unsigned long round8(unsigned long v)
10
+ {
11
+ if (v % 8 != 0) {
12
+ v += 8 - (v % 8);
13
+ }
14
+
15
+ return v;
16
+ }
17
+
18
+ /* clear any previous errors on a bitpack object */
19
+ static void _bitpack_err_clear(bitpack_t bp)
20
+ {
21
+ if (bp->error != BITPACK_ERR_CLEAR) {
22
+ bp->error = BITPACK_ERR_CLEAR;
23
+ memset(bp->error_str, '\0', BITPACK_ERR_BUF_SIZE);
24
+ }
25
+ }
26
+
27
+ /* increase the size of a bitpack object, allocating more memory if necessary */
28
+ static int _bitpack_resize(bitpack_t bp, unsigned long new_size)
29
+ {
30
+ unsigned long new_data_size = round8(new_size) / 8;
31
+
32
+ if (new_data_size > bp->data_size) {
33
+ bp->data = realloc(bp->data, new_data_size);
34
+
35
+ if (bp->data == NULL) {
36
+ bp->error = BITPACK_ERR_MALLOC_FAILED;
37
+ strncpy(bp->error_str, "memory allocation failed", BITPACK_ERR_BUF_SIZE);
38
+ return BITPACK_RV_ERROR;
39
+ }
40
+
41
+ memset(bp->data + bp->data_size, 0, new_data_size - bp->data_size);
42
+
43
+ bp->data_size = new_data_size;
44
+ }
45
+
46
+ bp->size = new_size;
47
+
48
+ return BITPACK_RV_SUCCESS;
49
+ }
50
+
51
+ bitpack_t bitpack_init(unsigned long num_bytes)
52
+ {
53
+ bitpack_t bp;
54
+ unsigned char *data;
55
+
56
+ bp = malloc(sizeof(struct _bitpack_t));
57
+ if (bp == NULL) return NULL;
58
+
59
+ data = malloc(num_bytes);
60
+
61
+ if (data == NULL) {
62
+ free(bp);
63
+ return NULL;
64
+ }
65
+
66
+ memset(data, 0, num_bytes);
67
+
68
+ bp->size = 0;
69
+ bp->read_pos = 0;
70
+ bp->data_size = num_bytes;
71
+ bp->data = data;
72
+ bp->error = BITPACK_ERR_CLEAR;
73
+ memset(bp->error_str, '\0', BITPACK_ERR_BUF_SIZE);
74
+
75
+ return bp;
76
+ }
77
+
78
+ bitpack_t bitpack_init_from_bytes(unsigned char *bytes, unsigned long num_bytes)
79
+ {
80
+ bitpack_t bp;
81
+
82
+ bp = bitpack_init(num_bytes);
83
+
84
+ if (bp == NULL) {
85
+ return NULL;
86
+ }
87
+
88
+ memcpy(bp->data, bytes, num_bytes);
89
+ bp->size = num_bytes * 8;
90
+
91
+ return bp;
92
+ }
93
+
94
+ void bitpack_destroy(bitpack_t bp)
95
+ {
96
+ free(bp->data);
97
+ free(bp);
98
+ }
99
+
100
+ unsigned long bitpack_size(bitpack_t bp)
101
+ {
102
+ return bp->size;
103
+ }
104
+
105
+ unsigned long bitpack_data_size(bitpack_t bp)
106
+ {
107
+ return bp->data_size;
108
+ }
109
+
110
+ unsigned long bitpack_read_pos(bitpack_t bp)
111
+ {
112
+ return bp->read_pos;
113
+ }
114
+
115
+ void bitpack_reset_read_pos(bitpack_t bp)
116
+ {
117
+ bp->read_pos = 0;
118
+ }
119
+
120
+ bitpack_err_t bitpack_get_error(bitpack_t bp)
121
+ {
122
+ return bp->error;
123
+ }
124
+
125
+ char *bitpack_get_error_str(bitpack_t bp)
126
+ {
127
+ return bp->error_str;
128
+ }
129
+
130
+ int bitpack_on(bitpack_t bp, unsigned long index)
131
+ {
132
+ unsigned long byte_offset;
133
+ unsigned long bit_offset;
134
+
135
+ _bitpack_err_clear(bp);
136
+
137
+ if (bitpack_size(bp) == 0 || index > bitpack_size(bp) - 1) {
138
+ if (!_bitpack_resize(bp, index + 1)) {
139
+ return BITPACK_RV_ERROR;
140
+ }
141
+ }
142
+
143
+ byte_offset = index / 8;
144
+ bit_offset = index % 8;
145
+
146
+ bp->data[byte_offset] |= (0x80 >> bit_offset);
147
+
148
+ return BITPACK_RV_SUCCESS;
149
+ }
150
+
151
+ int bitpack_off(bitpack_t bp, unsigned long index)
152
+ {
153
+ unsigned long byte_offset;
154
+ unsigned long bit_offset;
155
+
156
+ _bitpack_err_clear(bp);
157
+
158
+ if (bitpack_size(bp) == 0 || index > bitpack_size(bp) - 1) {
159
+ if (!_bitpack_resize(bp, index + 1)) {
160
+ return BITPACK_RV_ERROR;
161
+ }
162
+ }
163
+
164
+ byte_offset = index / 8;
165
+ bit_offset = index % 8;
166
+
167
+ bp->data[byte_offset] &= ~(0x80 >> bit_offset);
168
+
169
+ return BITPACK_RV_SUCCESS;
170
+ }
171
+
172
+ int bitpack_get(bitpack_t bp, unsigned long index, unsigned char *bit)
173
+ {
174
+ unsigned long byte_offset;
175
+ unsigned long bit_offset;
176
+
177
+ _bitpack_err_clear(bp);
178
+
179
+ if (bitpack_size(bp) == 0) {
180
+ bp->error = BITPACK_ERR_EMPTY;
181
+ strncpy(bp->error_str, "bitpack is empty", BITPACK_ERR_BUF_SIZE);
182
+ return BITPACK_RV_ERROR;
183
+ }
184
+
185
+ if (index > bitpack_size(bp) - 1) {
186
+ bp->error = BITPACK_ERR_INVALID_INDEX;
187
+ snprintf(bp->error_str, BITPACK_ERR_BUF_SIZE,
188
+ "invalid index (%lu), max index is %lu",
189
+ index, bitpack_size(bp) - 1);
190
+ return BITPACK_RV_ERROR;
191
+ }
192
+
193
+ byte_offset = index / 8;
194
+ bit_offset = index % 8;
195
+
196
+ if (bp->data[byte_offset] & (0x80 >> bit_offset)) {
197
+ *bit = 1;
198
+ }
199
+ else {
200
+ *bit = 0;
201
+ }
202
+
203
+ return BITPACK_RV_SUCCESS;
204
+ }
205
+
206
+ int bitpack_set_bits(bitpack_t bp, unsigned long value, unsigned long num_bits, unsigned long index)
207
+ {
208
+ unsigned long i;
209
+ unsigned long mask;
210
+
211
+ _bitpack_err_clear(bp);
212
+
213
+ /* make sure the range isn't bigger than the size of an unsigned long */
214
+ if (num_bits > sizeof(unsigned long) * 8) {
215
+ bp->error = BITPACK_ERR_RANGE_TOO_BIG;
216
+ snprintf(bp->error_str, BITPACK_ERR_BUF_SIZE,
217
+ "range size %lu bits is too large (maximum size is %lu bits)",
218
+ num_bits, sizeof(unsigned long) * 8);
219
+ return BITPACK_RV_ERROR;
220
+ }
221
+
222
+ /* make sure that the range is large enough to pack value */
223
+ if (value > pow(2, num_bits) - 1) {
224
+ bp->error = BITPACK_ERR_VALUE_TOO_BIG;
225
+ snprintf(bp->error_str, BITPACK_ERR_BUF_SIZE,
226
+ "value %lu does not fit in %lu bits",
227
+ value, num_bits);
228
+ return BITPACK_RV_ERROR;
229
+ }
230
+
231
+ if (bitpack_size(bp) < index + num_bits) {
232
+ if (!_bitpack_resize(bp, index + num_bits)) {
233
+ return BITPACK_RV_ERROR;
234
+ }
235
+ }
236
+
237
+ for (i = num_bits; i != 0; i--) {
238
+ mask = 1 << (i - 1);
239
+ if (value & mask) {
240
+ if (!bitpack_on(bp, index)) {
241
+ return BITPACK_RV_ERROR;
242
+ }
243
+ }
244
+ else {
245
+ if (!bitpack_off(bp, index)) {
246
+ return BITPACK_RV_ERROR;
247
+ }
248
+ }
249
+ index++;
250
+ }
251
+
252
+ return BITPACK_RV_SUCCESS;
253
+ }
254
+
255
+ int bitpack_set_bytes(bitpack_t bp, unsigned char *value, unsigned long num_bytes, unsigned long index)
256
+ {
257
+ unsigned long i;
258
+
259
+ _bitpack_err_clear(bp);
260
+
261
+ if (bitpack_size(bp) < index + num_bytes * 8) {
262
+ if (!_bitpack_resize(bp, index + num_bytes * 8)) {
263
+ return BITPACK_RV_ERROR;
264
+ }
265
+ }
266
+
267
+ if (index % 8 == 0) {
268
+ /* index is at the beginning of a byte, so just do a memcpy */
269
+ memcpy(bp->data + index / 8, value, num_bytes);
270
+ }
271
+ else {
272
+ /* need to set each bit individually */
273
+ for (i = 0; i < num_bytes; i++) {
274
+ if (!bitpack_set_bits(bp, value[i], 8, index + i * 8)) {
275
+ return BITPACK_RV_ERROR;
276
+ }
277
+ }
278
+ }
279
+
280
+ return BITPACK_RV_SUCCESS;
281
+ }
282
+
283
+ int bitpack_get_bits(bitpack_t bp, unsigned long num_bits, unsigned long index, unsigned long *value)
284
+ {
285
+ unsigned long i, v = 0;
286
+ unsigned char bit;
287
+
288
+ _bitpack_err_clear(bp);
289
+
290
+ if (index >= bitpack_size(bp)) {
291
+ bp->error = BITPACK_ERR_INVALID_INDEX;
292
+ snprintf(bp->error_str, BITPACK_ERR_BUF_SIZE,
293
+ "invalid index (%lu), max index is %lu",
294
+ index, bitpack_size(bp) - 1);
295
+ return BITPACK_RV_ERROR;
296
+ }
297
+
298
+ if (index + num_bits > bitpack_size(bp)) {
299
+ bp->error = BITPACK_ERR_READ_PAST_END;
300
+ snprintf(bp->error_str, BITPACK_ERR_BUF_SIZE,
301
+ "attempted to read past end of bitpack (last index is %lu)",
302
+ bitpack_size(bp) - 1);
303
+ return BITPACK_RV_ERROR;
304
+ }
305
+
306
+ if (num_bits > sizeof(unsigned long) * 8) {
307
+ bp->error = BITPACK_ERR_RANGE_TOO_BIG;
308
+ snprintf(bp->error_str, BITPACK_ERR_BUF_SIZE,
309
+ "range size %lu bits is too large (maximum size is %lu bits)",
310
+ num_bits, sizeof(unsigned long) * 8);
311
+ return BITPACK_RV_ERROR;
312
+ }
313
+
314
+ for (i = 0; i < num_bits; i++) {
315
+ bitpack_get(bp, index + i, &bit);
316
+
317
+ if (bit == 1) {
318
+ v |= bit << (num_bits - i - 1);
319
+ }
320
+ }
321
+
322
+ *value = v;
323
+
324
+ return BITPACK_RV_SUCCESS;
325
+ }
326
+
327
+ int bitpack_get_bytes(bitpack_t bp, unsigned long num_bytes, unsigned long index, unsigned char **value)
328
+ {
329
+ unsigned long i;
330
+ unsigned long byte;
331
+ unsigned char *unpacked;
332
+
333
+ _bitpack_err_clear(bp);
334
+
335
+ if (index >= bitpack_size(bp)) {
336
+ bp->error = BITPACK_ERR_INVALID_INDEX;
337
+ snprintf(bp->error_str, BITPACK_ERR_BUF_SIZE,
338
+ "invalid index (%lu), max index is %lu",
339
+ index, bitpack_size(bp) - 1);
340
+ return BITPACK_RV_ERROR;
341
+ }
342
+
343
+ if (index + num_bytes * 8 > bitpack_size(bp)) {
344
+ bp->error = BITPACK_ERR_READ_PAST_END;
345
+ snprintf(bp->error_str, BITPACK_ERR_BUF_SIZE,
346
+ "attempted to read past end of bitpack (last index is %lu)",
347
+ bitpack_size(bp) - 1);
348
+ return BITPACK_RV_ERROR;
349
+ }
350
+
351
+ unpacked = malloc(num_bytes);
352
+ if (unpacked == NULL) {
353
+ bp->error = BITPACK_ERR_MALLOC_FAILED;
354
+ strncpy(bp->error_str, "memory allocation failed", BITPACK_ERR_BUF_SIZE);
355
+ return BITPACK_RV_ERROR;
356
+ }
357
+
358
+ if (index % 8 == 0) {
359
+ /* index is the start of a byte, so just do a memcpy */
360
+ memcpy(unpacked, bp->data + index / 8, num_bytes);
361
+ }
362
+ else {
363
+ /* need to unpack a byte at a time */
364
+ for (i = 0; i < num_bytes; i++) {
365
+ bitpack_get_bits(bp, 8, index + i * 8, &byte);
366
+ unpacked[i] = byte;
367
+ }
368
+ }
369
+
370
+ *value = unpacked;
371
+
372
+ return BITPACK_RV_SUCCESS;
373
+ }
374
+
375
+ int bitpack_read_bits(bitpack_t bp, unsigned long num_bits, unsigned long *value)
376
+ {
377
+ int rv;
378
+
379
+ _bitpack_err_clear(bp);
380
+
381
+ if (bp->read_pos + num_bits > bitpack_size(bp)) {
382
+ bp->error = BITPACK_ERR_READ_PAST_END;
383
+ snprintf(bp->error_str, BITPACK_ERR_BUF_SIZE,
384
+ "attempted to read past end of bitpack (last index is %lu)",
385
+ bitpack_size(bp) - 1);
386
+ return BITPACK_RV_ERROR;
387
+ }
388
+
389
+ rv = bitpack_get_bits(bp, num_bits, bp->read_pos, value);
390
+
391
+ if (rv == BITPACK_RV_SUCCESS) {
392
+ bp->read_pos += num_bits;
393
+ }
394
+ else {
395
+ return rv;
396
+ }
397
+
398
+ return BITPACK_RV_SUCCESS;
399
+ }
400
+
401
+ int bitpack_read_bytes(bitpack_t bp, unsigned long num_bytes, unsigned char **value)
402
+ {
403
+ int rv;
404
+
405
+ _bitpack_err_clear(bp);
406
+
407
+ if (bp->read_pos + num_bytes * 8 > bitpack_size(bp)) {
408
+ bp->error = BITPACK_ERR_READ_PAST_END;
409
+ snprintf(bp->error_str, BITPACK_ERR_BUF_SIZE,
410
+ "attempted to read past end of bitpack (last index is %lu)",
411
+ bitpack_size(bp) - 1);
412
+ return BITPACK_RV_ERROR;
413
+ }
414
+
415
+ rv = bitpack_get_bytes(bp, num_bytes, bp->read_pos, value);
416
+
417
+ if (rv == BITPACK_RV_SUCCESS) {
418
+ bp->read_pos += num_bytes * 8;
419
+ }
420
+ else {
421
+ return rv;
422
+ }
423
+
424
+ return BITPACK_RV_SUCCESS;
425
+ }
426
+
427
+ int bitpack_to_bin(bitpack_t bp, char **str)
428
+ {
429
+ unsigned long i;
430
+ char *string;
431
+ char tmp[3];
432
+ unsigned char bit;
433
+
434
+ _bitpack_err_clear(bp);
435
+
436
+ string = malloc(bitpack_size(bp) + 1);
437
+
438
+ if (string == NULL) {
439
+ *str = NULL;
440
+ bp->error = BITPACK_ERR_MALLOC_FAILED;
441
+ strncpy(bp->error_str, "memory allocation failed", BITPACK_ERR_BUF_SIZE);
442
+ return BITPACK_RV_ERROR;
443
+ }
444
+
445
+ string[0] = '\0';
446
+
447
+ for (i = 0; i < bitpack_size(bp); i++) {
448
+ bitpack_get(bp, i, &bit);
449
+ sprintf(tmp, "%d", bit);
450
+ strncat(string, tmp, 1);
451
+ }
452
+
453
+ *str = string;
454
+
455
+ return BITPACK_RV_SUCCESS;
456
+ }
457
+
458
+ int bitpack_to_bytes(bitpack_t bp, unsigned char **value, unsigned long *num_bytes)
459
+ {
460
+ unsigned char *bytes;
461
+ unsigned long bytes_size = round8(bp->size) / 8;
462
+
463
+ _bitpack_err_clear(bp);
464
+
465
+ bytes = malloc(bytes_size);
466
+
467
+ if (bytes == NULL) {
468
+ bp->error = BITPACK_ERR_MALLOC_FAILED;
469
+ strncpy(bp->error_str, "memory allocation failed", BITPACK_ERR_BUF_SIZE);
470
+ return BITPACK_RV_ERROR;
471
+ }
472
+
473
+ memcpy(bytes, bp->data, bytes_size);
474
+
475
+ *value = bytes;
476
+
477
+ if (num_bytes) {
478
+ *num_bytes = bytes_size;
479
+ }
480
+
481
+ return BITPACK_RV_SUCCESS;
482
+ }
483
+