Skip to content

Commit ae2a3b3

Browse files
authored
Merge pull request #457 from s-hadinger/bytes_appendhex_appendb64
Add 'bytes.appendhex()' and 'bytes.appendb64()'
2 parents 5aa0d1e + 5e583ec commit ae2a3b3

File tree

2 files changed

+94
-8
lines changed

2 files changed

+94
-8
lines changed

src/be_byteslib.c

+70-8
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
#include <ctype.h>
1919
#include "be_byteslib.h"
2020

21+
static const char * hex = "0123456789ABCDEF";
22+
2123
/********************************************************************
2224
** Base64 lib from https://github.com/Densaugeo/base64_arduino
2325
**
@@ -715,7 +717,6 @@ buf_impl bytes_check_data(bvm *vm, size_t add_size) {
715717
}
716718

717719
size_t be_bytes_tohex(char * out, size_t outsz, const uint8_t * in, size_t insz) {
718-
static const char * hex = "0123456789ABCDEF";
719720
const uint8_t * pin = in;
720721
char * pout = out;
721722
for (; pin < in + insz; pout += 2, pin++) {
@@ -1317,7 +1318,7 @@ static int m_copy(bvm *vm)
13171318
be_return(vm); /* return self */
13181319
}
13191320

1320-
/* accept bytes or int as operand */
1321+
/* accept bytes or int or nil as operand */
13211322
static int m_connect(bvm *vm)
13221323
{
13231324
int argc = be_top(vm);
@@ -1329,8 +1330,6 @@ static int m_connect(bvm *vm)
13291330
bytes_resize(vm, &attr, attr.len + 1); /* resize */
13301331
buf_add1(&attr, be_toint(vm, 2));
13311332
m_write_attributes(vm, 1, &attr); /* update instance */
1332-
be_pushvalue(vm, 1);
1333-
be_return(vm); /* return self */
13341333
} else if (be_isstring(vm, 2)) {
13351334
const char *str = be_tostring(vm, 2);
13361335
size_t str_len = strlen(str);
@@ -1339,22 +1338,81 @@ static int m_connect(bvm *vm)
13391338
buf_add_raw(&attr, str, str_len);
13401339
m_write_attributes(vm, 1, &attr); /* update instance */
13411340
}
1342-
be_pushvalue(vm, 1);
1343-
be_return(vm); /* return self */
13441341
} else {
13451342
buf_impl attr2 = m_read_attributes(vm, 2);
13461343
check_ptr(vm, &attr2);
13471344
bytes_resize(vm, &attr, attr.len + attr2.len); /* resize buf1 for total size */
13481345
buf_add_buf(&attr, &attr2);
13491346
m_write_attributes(vm, 1, &attr); /* update instance */
1350-
be_pushvalue(vm, 1);
1351-
be_return(vm); /* return self */
13521347
}
1348+
be_pushvalue(vm, 1);
1349+
be_return(vm); /* return self */
13531350
}
13541351
be_raise(vm, "type_error", "operand must be bytes or int or string");
13551352
be_return_nil(vm); /* return self */
13561353
}
13571354

1355+
static int m_appendhex(bvm *vm)
1356+
{
1357+
int argc = be_top(vm);
1358+
buf_impl attr = m_read_attributes(vm, 1);
1359+
check_ptr_modifiable(vm, &attr);
1360+
if (attr.fixed) { be_raise(vm, BYTES_RESIZE_ERROR, BYTES_RESIZE_MESSAGE); }
1361+
if (argc >= 2 && be_isbytes(vm, 2)) {
1362+
buf_impl attr2 = m_read_attributes(vm, 2);
1363+
check_ptr(vm, &attr2);
1364+
bytes_resize(vm, &attr, attr.len + attr2.len * 2); /* resize */
1365+
1366+
for (const uint8_t * pin = attr2.bufptr; pin < attr2.bufptr + attr2.len; pin++) {
1367+
buf_add1(&attr, hex[((*pin)>>4) & 0xF]);
1368+
buf_add1(&attr, hex[ (*pin) & 0xF]);
1369+
}
1370+
1371+
m_write_attributes(vm, 1, &attr); /* update instance */
1372+
be_pushvalue(vm, 1);
1373+
be_return(vm); /* return self */
1374+
}
1375+
be_raise(vm, "type_error", "operand must be bytes");
1376+
be_return_nil(vm); /* return self */
1377+
}
1378+
1379+
static int m_appendb64(bvm *vm)
1380+
{
1381+
int argc = be_top(vm);
1382+
buf_impl attr = m_read_attributes(vm, 1);
1383+
check_ptr_modifiable(vm, &attr);
1384+
if (attr.fixed) { be_raise(vm, BYTES_RESIZE_ERROR, BYTES_RESIZE_MESSAGE); }
1385+
if (argc >= 2 && be_isbytes(vm, 2)) {
1386+
buf_impl attr2 = m_read_attributes(vm, 2);
1387+
check_ptr(vm, &attr2);
1388+
int32_t idx = 0; /* start from index 0 */
1389+
int32_t len = attr2.len; /* entire len */
1390+
if (argc >= 3 && be_isint(vm, 3)) { /* read optional idx and len */
1391+
idx = be_toint(vm, 3);
1392+
if (idx < 0) { idx = attr2.len + idx; } /* if negative, count from end */
1393+
if (idx < 0) { idx = 0; } /* guardrails */
1394+
if (idx > attr2.len) { idx = attr2.len; }
1395+
if (argc >= 4 && be_isint(vm, 4)) {
1396+
len = be_toint(vm, 4);
1397+
if (len < 0) { len = 0; }
1398+
}
1399+
if (idx + len >= attr2.len) { len = attr2.len - idx; }
1400+
}
1401+
if (len > 0) { /* only if there is something to encode */
1402+
bytes_resize(vm, &attr, attr.len + encode_base64_length(len) + 1); /* resize */
1403+
1404+
size_t converted = encode_base64(attr2.bufptr + idx, len, (unsigned char*)(attr.bufptr + attr.len));
1405+
attr.len += converted;
1406+
1407+
m_write_attributes(vm, 1, &attr); /* update instance */
1408+
}
1409+
be_pushvalue(vm, 1);
1410+
be_return(vm); /* return self */
1411+
}
1412+
be_raise(vm, "type_error", "operand must be bytes");
1413+
be_return_nil(vm); /* return self */
1414+
}
1415+
13581416
static int bytes_equal(bvm *vm, bbool iseq)
13591417
{
13601418
bbool ret;
@@ -1841,6 +1899,8 @@ void be_load_byteslib(bvm *vm)
18411899
{ "reverse", m_reverse },
18421900
{ "copy", m_copy },
18431901
{ "append", m_connect },
1902+
{ "appendhex", m_appendhex },
1903+
{ "appendb64", m_appendb64 },
18441904
{ "+", m_merge },
18451905
{ "..", m_connect },
18461906
{ "==", m_equal },
@@ -1894,6 +1954,8 @@ class be_class_bytes (scope: global, name: bytes) {
18941954
reverse, func(m_reverse)
18951955
copy, func(m_copy)
18961956
append, func(m_connect)
1957+
appendhex, func(m_appendhex)
1958+
appendb64, func(m_appendb64)
18971959
+, func(m_merge)
18981960
.., func(m_connect)
18991961
==, func(m_equal)

tests/bytes.be

+24
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,11 @@ assert(str(b1) == "bytes('AA')")
155155
b1.append('01')
156156
assert(str(b1) == "bytes('AA3031')")
157157

158+
#- appendhex -#
159+
assert(bytes().appendhex(bytes("DEADBEEF")) == bytes("4445414442454546"))
160+
assert(bytes("AABBCC").appendhex(bytes("DEADBEEF")) == bytes("AABBCC4445414442454546"))
161+
assert(bytes("AABBCC").appendhex(bytes("")) == bytes("AABBCC"))
162+
158163
#- item -#
159164
b = bytes("334455")
160165
assert(b[0] == 0x33)
@@ -325,3 +330,22 @@ assert(bytes("02"))
325330
a = bytes("01020304")
326331
assert(a.get(1, 3) == 0x040302)
327332
assert(a.get(1, -3) == 0x020304)
333+
334+
# append base64
335+
b = bytes("AABBCC")
336+
c = bytes("001122")
337+
assert(bytes().fromstring(bytes("001122").tob64()) == bytes('41424569'))
338+
assert(b.appendb64(c) == bytes("AABBCC41424569"))
339+
assert(b.appendb64(bytes()) == bytes("AABBCC41424569"))
340+
341+
b = bytes("AABBCC")
342+
assert(bytes().fromstring(bytes("1122").tob64()) == bytes('4553493D'))
343+
assert(b.appendb64(c, 1) == bytes("AABBCC4553493D"))
344+
345+
b = bytes("AABBCC")
346+
assert(bytes().fromstring(bytes("22").tob64()) == bytes('49673D3D'))
347+
assert(b.appendb64(c, 2) == bytes("AABBCC49673D3D"))
348+
349+
b = bytes("AABBCC")
350+
assert(bytes().fromstring(bytes("11").tob64()) == bytes('45513D3D'))
351+
assert(b.appendb64(c, 1, 1) == bytes("AABBCC45513D3D"))

0 commit comments

Comments
 (0)