@@ -39,6 +39,7 @@ enum pack_dir {
3939PACK_DIR_FLOAT, /* f */
4040PACK_DIR_STR, /* A */
4141PACK_DIR_HEX, /* h */
42+PACK_DIR_BSTR, /* b */
4243PACK_DIR_BASE64, /* m */
4344PACK_DIR_QENC, /* M */
4445PACK_DIR_NUL, /* x */
@@ -859,6 +860,92 @@ unpack_hex(mrb_state *mrb, const void *src, int slen, mrb_value ary, int count,
859860return (int)(sptr - sptr0);
860861}
861862863+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+862949static int
863950pack_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
12001287type = PACK_TYPE_STRING;
12011288flags |= PACK_FLAG_COUNT2 | PACK_FLAG_LSB;
12021289break;
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;
12031300case 'I':
12041301switch (sizeof(int)) {
12051302case 2: t = 'S'; goto alias;
@@ -1483,6 +1580,9 @@ mrb_pack_pack(mrb_state *mrb, mrb_value ary)
14831580case PACK_DIR_HEX:
14841581ridx += pack_hex(mrb, o, result, ridx, count, flags);
14851582break;
1583+case PACK_DIR_BSTR:
1584+ridx += pack_bstr(mrb, o, result, ridx, count, flags);
1585+break;
14861586case PACK_DIR_STR:
14871587ridx += pack_str(mrb, o, result, ridx, count, flags);
14881588break;
@@ -1565,6 +1665,9 @@ pack_unpack(mrb_state *mrb, mrb_value str, int single)
15651665case PACK_DIR_HEX:
15661666srcidx += unpack_hex(mrb, sptr, srclen - srcidx, result, count, flags);
15671667continue;
1668+case PACK_DIR_BSTR:
1669+srcidx += unpack_bstr(mrb, sptr, srclen - srcidx, result, count, flags);
1670+continue;
15681671case PACK_DIR_STR:
15691672srcidx += unpack_str(mrb, sptr, srclen - srcidx, result, count, flags);
15701673continue;