Skip to content

Commit e7021f1

Browse files
committed
mruby-pack/pack.c (pack_bstr): support B/b directives
1 parent 0554941 commit e7021f1

File tree

2 files changed

+105
-0
lines changed

2 files changed

+105
-0
lines changed

mrbgems/mruby-pack/README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ There is no dependency on other mrbgems.
1616

1717
- A : arbitrary binary string (space padded, count is width)
1818
- a : arbitrary binary string (null padded, count is width)
19+
- B : bit string (descending)
20+
- b : bit string (ascending)
1921
- C : 8-bit unsigned (unsigned char)
2022
- c : 8-bit signed (signed char)
2123
- D, d: 64-bit float, native format

mrbgems/mruby-pack/src/pack.c

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ enum pack_dir {
3939
PACK_DIR_FLOAT, /* f */
4040
PACK_DIR_STR, /* A */
4141
PACK_DIR_HEX, /* h */
42+
PACK_DIR_BSTR, /* b */
4243
PACK_DIR_BASE64, /* m */
4344
PACK_DIR_QENC, /* M */
4445
PACK_DIR_NUL, /* x */
@@ -859,6 +860,92 @@ unpack_hex(mrb_state *mrb, const void *src, int slen, mrb_value ary, int count,
859860
return (int)(sptr - sptr0);
860861
}
861862

863+
static int
864+
pack_bstr(mrb_state *mrb, mrb_value src, mrb_value dst, mrb_int didx, int count, unsigned int flags)
865+
{
866+
const char *sptr = RSTRING_PTR(src);
867+
int slen = (int)RSTRING_LEN(src);
868+
869+
if (count == -1) {
870+
count = slen;
871+
}
872+
else if (slen > count) {
873+
slen = count;
874+
}
875+
876+
dst = str_len_ensure(mrb, dst, didx + count);
877+
char *dptr = RSTRING_PTR(dst) + didx;
878+
char *dptr0 = dptr;
879+
880+
unsigned int byte = 0;
881+
for (int i=0; i++ < slen; sptr++) {
882+
if (flags & PACK_FLAG_LSB) {
883+
if (*sptr & 1)
884+
byte |= 128;
885+
if (i & 7)
886+
byte >>= 1;
887+
else {
888+
char c = (char)(byte&0xff);
889+
*dptr++ = c;
890+
byte = 0;
891+
}
892+
}
893+
else {
894+
byte |= *sptr & 1;
895+
if (i & 7)
896+
byte <<= 1;
897+
else {
898+
char c = (char)(byte&0xff);
899+
*dptr++ = c;
900+
byte = 0;
901+
}
902+
}
903+
}
904+
if (slen & 7) {
905+
if (flags & PACK_FLAG_LSB) {
906+
byte >>= 7 - (slen & 7);
907+
}
908+
else {
909+
byte <<= 7 - (slen & 7);
910+
}
911+
char c = (char)(byte&0xff);
912+
*dptr++ = c;
913+
}
914+
return (int)(dptr - dptr0);
915+
}
916+
917+
static int
918+
unpack_bstr(mrb_state *mrb, const void *src, int slen, mrb_value ary, int count, unsigned int flags)
919+
{
920+
CHECK_UNPACK_LEN(mrb, slen, ary);
921+
922+
const char *sptr0 = (const char*)src;
923+
const char *sptr = sptr0;
924+
if (count == -1)
925+
count = slen * 8;
926+
927+
mrb_value dst = mrb_str_new(mrb, NULL, count);
928+
char *dptr = RSTRING_PTR(dst);
929+
const char *dptr0 = dptr;
930+
int bits = 0;
931+
932+
for (int i=0; i<count; i++) {
933+
if (flags & PACK_FLAG_LSB) {
934+
if (i & 7) bits >>= 1;
935+
else bits = (unsigned char)*sptr++;
936+
*dptr++ = (bits & 1) ? '1' : '0';
937+
}
938+
else {
939+
if (i & 7) bits <<= 1;
940+
else bits = (unsigned char)*sptr++;
941+
*dptr++ = (bits & 128) ? '1' : '0';
942+
}
943+
}
944+
dst = mrb_str_resize(mrb, dst, (mrb_int)(dptr - dptr0));
945+
mrb_ary_push(mrb, ary, dst);
946+
return (int)(sptr - sptr0);
947+
}
948+
862949
static int
863950
pack_base64(mrb_state *mrb, mrb_value src, mrb_value dst, mrb_int didx, int count)
864951
{
@@ -1200,6 +1287,16 @@ read_tmpl(mrb_state *mrb, struct tmpl *tmpl, enum pack_dir *dirp, enum pack_type
12001287
type = PACK_TYPE_STRING;
12011288
flags |= PACK_FLAG_COUNT2 | PACK_FLAG_LSB;
12021289
break;
1290+
case 'B':
1291+
dir = PACK_DIR_BSTR;
1292+
type = PACK_TYPE_STRING;
1293+
flags |= PACK_FLAG_COUNT2;
1294+
break;
1295+
case 'b':
1296+
dir = PACK_DIR_BSTR;
1297+
type = PACK_TYPE_STRING;
1298+
flags |= PACK_FLAG_COUNT2 | PACK_FLAG_LSB;
1299+
break;
12031300
case 'I':
12041301
switch (sizeof(int)) {
12051302
case 2: t = 'S'; goto alias;
@@ -1483,6 +1580,9 @@ mrb_pack_pack(mrb_state *mrb, mrb_value ary)
14831580
case PACK_DIR_HEX:
14841581
ridx += pack_hex(mrb, o, result, ridx, count, flags);
14851582
break;
1583+
case PACK_DIR_BSTR:
1584+
ridx += pack_bstr(mrb, o, result, ridx, count, flags);
1585+
break;
14861586
case PACK_DIR_STR:
14871587
ridx += pack_str(mrb, o, result, ridx, count, flags);
14881588
break;
@@ -1565,6 +1665,9 @@ pack_unpack(mrb_state *mrb, mrb_value str, int single)
15651665
case PACK_DIR_HEX:
15661666
srcidx += unpack_hex(mrb, sptr, srclen - srcidx, result, count, flags);
15671667
continue;
1668+
case PACK_DIR_BSTR:
1669+
srcidx += unpack_bstr(mrb, sptr, srclen - srcidx, result, count, flags);
1670+
continue;
15681671
case PACK_DIR_STR:
15691672
srcidx += unpack_str(mrb, sptr, srclen - srcidx, result, count, flags);
15701673
continue;

0 commit comments

Comments
 (0)