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
717719size_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 */
13211322static 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+
13581416static 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)
0 commit comments