18
18
#include <ctype.h>
19
19
#include "be_byteslib.h"
20
20
21
+ static const char * hex = "0123456789ABCDEF" ;
22
+
21
23
/********************************************************************
22
24
** Base64 lib from https://github.com/Densaugeo/base64_arduino
23
25
**
@@ -715,7 +717,6 @@ buf_impl bytes_check_data(bvm *vm, size_t add_size) {
715
717
}
716
718
717
719
size_t be_bytes_tohex (char * out , size_t outsz , const uint8_t * in , size_t insz ) {
718
- static const char * hex = "0123456789ABCDEF" ;
719
720
const uint8_t * pin = in ;
720
721
char * pout = out ;
721
722
for (; pin < in + insz ; pout += 2 , pin ++ ) {
@@ -1317,7 +1318,7 @@ static int m_copy(bvm *vm)
1317
1318
be_return (vm ); /* return self */
1318
1319
}
1319
1320
1320
- /* accept bytes or int as operand */
1321
+ /* accept bytes or int or nil as operand */
1321
1322
static int m_connect (bvm * vm )
1322
1323
{
1323
1324
int argc = be_top (vm );
@@ -1329,8 +1330,6 @@ static int m_connect(bvm *vm)
1329
1330
bytes_resize (vm , & attr , attr .len + 1 ); /* resize */
1330
1331
buf_add1 (& attr , be_toint (vm , 2 ));
1331
1332
m_write_attributes (vm , 1 , & attr ); /* update instance */
1332
- be_pushvalue (vm , 1 );
1333
- be_return (vm ); /* return self */
1334
1333
} else if (be_isstring (vm , 2 )) {
1335
1334
const char * str = be_tostring (vm , 2 );
1336
1335
size_t str_len = strlen (str );
@@ -1339,22 +1338,81 @@ static int m_connect(bvm *vm)
1339
1338
buf_add_raw (& attr , str , str_len );
1340
1339
m_write_attributes (vm , 1 , & attr ); /* update instance */
1341
1340
}
1342
- be_pushvalue (vm , 1 );
1343
- be_return (vm ); /* return self */
1344
1341
} else {
1345
1342
buf_impl attr2 = m_read_attributes (vm , 2 );
1346
1343
check_ptr (vm , & attr2 );
1347
1344
bytes_resize (vm , & attr , attr .len + attr2 .len ); /* resize buf1 for total size */
1348
1345
buf_add_buf (& attr , & attr2 );
1349
1346
m_write_attributes (vm , 1 , & attr ); /* update instance */
1350
- be_pushvalue (vm , 1 );
1351
- be_return (vm ); /* return self */
1352
1347
}
1348
+ be_pushvalue (vm , 1 );
1349
+ be_return (vm ); /* return self */
1353
1350
}
1354
1351
be_raise (vm , "type_error" , "operand must be bytes or int or string" );
1355
1352
be_return_nil (vm ); /* return self */
1356
1353
}
1357
1354
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
+
1358
1416
static int bytes_equal (bvm * vm , bbool iseq )
1359
1417
{
1360
1418
bbool ret ;
@@ -1841,6 +1899,8 @@ void be_load_byteslib(bvm *vm)
1841
1899
{ "reverse" , m_reverse },
1842
1900
{ "copy" , m_copy },
1843
1901
{ "append" , m_connect },
1902
+ { "appendhex" , m_appendhex },
1903
+ { "appendb64" , m_appendb64 },
1844
1904
{ "+" , m_merge },
1845
1905
{ ".." , m_connect },
1846
1906
{ "==" , m_equal },
@@ -1894,6 +1954,8 @@ class be_class_bytes (scope: global, name: bytes) {
1894
1954
reverse, func(m_reverse)
1895
1955
copy, func(m_copy)
1896
1956
append, func(m_connect)
1957
+ appendhex, func(m_appendhex)
1958
+ appendb64, func(m_appendb64)
1897
1959
+, func(m_merge)
1898
1960
.., func(m_connect)
1899
1961
==, func(m_equal)
0 commit comments