Skip to content

Commit

Permalink
Merge pull request #457 from s-hadinger/bytes_appendhex_appendb64
Browse files Browse the repository at this point in the history
Add 'bytes.appendhex()' and 'bytes.appendb64()'
  • Loading branch information
skiars authored Feb 26, 2025
2 parents 5aa0d1e + 5e583ec commit ae2a3b3
Show file tree
Hide file tree
Showing 2 changed files with 94 additions and 8 deletions.
78 changes: 70 additions & 8 deletions src/be_byteslib.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
#include <ctype.h>
#include "be_byteslib.h"

static const char * hex = "0123456789ABCDEF";

/********************************************************************
** Base64 lib from https://github.com/Densaugeo/base64_arduino
**
Expand Down Expand Up @@ -715,7 +717,6 @@ buf_impl bytes_check_data(bvm *vm, size_t add_size) {
}

size_t be_bytes_tohex(char * out, size_t outsz, const uint8_t * in, size_t insz) {
static const char * hex = "0123456789ABCDEF";
const uint8_t * pin = in;
char * pout = out;
for (; pin < in + insz; pout += 2, pin++) {
Expand Down Expand Up @@ -1317,7 +1318,7 @@ static int m_copy(bvm *vm)
be_return(vm); /* return self */
}

/* accept bytes or int as operand */
/* accept bytes or int or nil as operand */
static int m_connect(bvm *vm)
{
int argc = be_top(vm);
Expand All @@ -1329,8 +1330,6 @@ static int m_connect(bvm *vm)
bytes_resize(vm, &attr, attr.len + 1); /* resize */
buf_add1(&attr, be_toint(vm, 2));
m_write_attributes(vm, 1, &attr); /* update instance */
be_pushvalue(vm, 1);
be_return(vm); /* return self */
} else if (be_isstring(vm, 2)) {
const char *str = be_tostring(vm, 2);
size_t str_len = strlen(str);
Expand All @@ -1339,22 +1338,81 @@ static int m_connect(bvm *vm)
buf_add_raw(&attr, str, str_len);
m_write_attributes(vm, 1, &attr); /* update instance */
}
be_pushvalue(vm, 1);
be_return(vm); /* return self */
} else {
buf_impl attr2 = m_read_attributes(vm, 2);
check_ptr(vm, &attr2);
bytes_resize(vm, &attr, attr.len + attr2.len); /* resize buf1 for total size */
buf_add_buf(&attr, &attr2);
m_write_attributes(vm, 1, &attr); /* update instance */
be_pushvalue(vm, 1);
be_return(vm); /* return self */
}
be_pushvalue(vm, 1);
be_return(vm); /* return self */
}
be_raise(vm, "type_error", "operand must be bytes or int or string");
be_return_nil(vm); /* return self */
}

static int m_appendhex(bvm *vm)
{
int argc = be_top(vm);
buf_impl attr = m_read_attributes(vm, 1);
check_ptr_modifiable(vm, &attr);
if (attr.fixed) { be_raise(vm, BYTES_RESIZE_ERROR, BYTES_RESIZE_MESSAGE); }
if (argc >= 2 && be_isbytes(vm, 2)) {
buf_impl attr2 = m_read_attributes(vm, 2);
check_ptr(vm, &attr2);
bytes_resize(vm, &attr, attr.len + attr2.len * 2); /* resize */

for (const uint8_t * pin = attr2.bufptr; pin < attr2.bufptr + attr2.len; pin++) {
buf_add1(&attr, hex[((*pin)>>4) & 0xF]);
buf_add1(&attr, hex[ (*pin) & 0xF]);
}

m_write_attributes(vm, 1, &attr); /* update instance */
be_pushvalue(vm, 1);
be_return(vm); /* return self */
}
be_raise(vm, "type_error", "operand must be bytes");
be_return_nil(vm); /* return self */
}

static int m_appendb64(bvm *vm)
{
int argc = be_top(vm);
buf_impl attr = m_read_attributes(vm, 1);
check_ptr_modifiable(vm, &attr);
if (attr.fixed) { be_raise(vm, BYTES_RESIZE_ERROR, BYTES_RESIZE_MESSAGE); }
if (argc >= 2 && be_isbytes(vm, 2)) {
buf_impl attr2 = m_read_attributes(vm, 2);
check_ptr(vm, &attr2);
int32_t idx = 0; /* start from index 0 */
int32_t len = attr2.len; /* entire len */
if (argc >= 3 && be_isint(vm, 3)) { /* read optional idx and len */
idx = be_toint(vm, 3);
if (idx < 0) { idx = attr2.len + idx; } /* if negative, count from end */
if (idx < 0) { idx = 0; } /* guardrails */
if (idx > attr2.len) { idx = attr2.len; }
if (argc >= 4 && be_isint(vm, 4)) {
len = be_toint(vm, 4);
if (len < 0) { len = 0; }
}
if (idx + len >= attr2.len) { len = attr2.len - idx; }
}
if (len > 0) { /* only if there is something to encode */
bytes_resize(vm, &attr, attr.len + encode_base64_length(len) + 1); /* resize */

size_t converted = encode_base64(attr2.bufptr + idx, len, (unsigned char*)(attr.bufptr + attr.len));
attr.len += converted;

m_write_attributes(vm, 1, &attr); /* update instance */
}
be_pushvalue(vm, 1);
be_return(vm); /* return self */
}
be_raise(vm, "type_error", "operand must be bytes");
be_return_nil(vm); /* return self */
}

static int bytes_equal(bvm *vm, bbool iseq)
{
bbool ret;
Expand Down Expand Up @@ -1841,6 +1899,8 @@ void be_load_byteslib(bvm *vm)
{ "reverse", m_reverse },
{ "copy", m_copy },
{ "append", m_connect },
{ "appendhex", m_appendhex },
{ "appendb64", m_appendb64 },
{ "+", m_merge },
{ "..", m_connect },
{ "==", m_equal },
Expand Down Expand Up @@ -1894,6 +1954,8 @@ class be_class_bytes (scope: global, name: bytes) {
reverse, func(m_reverse)
copy, func(m_copy)
append, func(m_connect)
appendhex, func(m_appendhex)
appendb64, func(m_appendb64)
+, func(m_merge)
.., func(m_connect)
==, func(m_equal)
Expand Down
24 changes: 24 additions & 0 deletions tests/bytes.be
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,11 @@ assert(str(b1) == "bytes('AA')")
b1.append('01')
assert(str(b1) == "bytes('AA3031')")

#- appendhex -#
assert(bytes().appendhex(bytes("DEADBEEF")) == bytes("4445414442454546"))
assert(bytes("AABBCC").appendhex(bytes("DEADBEEF")) == bytes("AABBCC4445414442454546"))
assert(bytes("AABBCC").appendhex(bytes("")) == bytes("AABBCC"))

#- item -#
b = bytes("334455")
assert(b[0] == 0x33)
Expand Down Expand Up @@ -325,3 +330,22 @@ assert(bytes("02"))
a = bytes("01020304")
assert(a.get(1, 3) == 0x040302)
assert(a.get(1, -3) == 0x020304)

# append base64
b = bytes("AABBCC")
c = bytes("001122")
assert(bytes().fromstring(bytes("001122").tob64()) == bytes('41424569'))
assert(b.appendb64(c) == bytes("AABBCC41424569"))
assert(b.appendb64(bytes()) == bytes("AABBCC41424569"))

b = bytes("AABBCC")
assert(bytes().fromstring(bytes("1122").tob64()) == bytes('4553493D'))
assert(b.appendb64(c, 1) == bytes("AABBCC4553493D"))

b = bytes("AABBCC")
assert(bytes().fromstring(bytes("22").tob64()) == bytes('49673D3D'))
assert(b.appendb64(c, 2) == bytes("AABBCC49673D3D"))

b = bytes("AABBCC")
assert(bytes().fromstring(bytes("11").tob64()) == bytes('45513D3D'))
assert(b.appendb64(c, 1, 1) == bytes("AABBCC45513D3D"))

0 comments on commit ae2a3b3

Please sign in to comment.