From 5e583ec0a5f6f13aff3dbe1e2a4e01a1944233b8 Mon Sep 17 00:00:00 2001 From: s-hadinger <49731213+s-hadinger@users.noreply.github.com> Date: Sat, 22 Feb 2025 11:20:30 +0100 Subject: [PATCH] Add 'bytes.appendhex()' and 'bytes.appendb64()' --- src/be_byteslib.c | 78 ++++++++++++++++++++++++++++++++++++++++++----- tests/bytes.be | 24 +++++++++++++++ 2 files changed, 94 insertions(+), 8 deletions(-) diff --git a/src/be_byteslib.c b/src/be_byteslib.c index 460de41..1ddd027 100644 --- a/src/be_byteslib.c +++ b/src/be_byteslib.c @@ -18,6 +18,8 @@ #include #include "be_byteslib.h" +static const char * hex = "0123456789ABCDEF"; + /******************************************************************** ** Base64 lib from https://github.com/Densaugeo/base64_arduino ** @@ -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++) { @@ -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); @@ -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); @@ -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; @@ -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 }, @@ -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) diff --git a/tests/bytes.be b/tests/bytes.be index 1f58118..0cdc833 100644 --- a/tests/bytes.be +++ b/tests/bytes.be @@ -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) @@ -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"))