66
77using namespace Pinetime ::Applications::Screens;
88
9+ #define LOG_PREFIX " [Pawn] "
10+
911enum {
1012 PAWN_ERR_PARAMCOUNT = 100 ,
1113 PAWN_ERR_MISSINGHANDLER,
1214 PAWN_ERR_INVALIDSTRING,
1315 PAWN_ERR_INVALIDSETTING,
1416 PAWN_ERR_INVALIDTRAMPOLINE,
17+ PAWN_ERR_FILE,
1518
1619 PAWN_ERR_FIRST = PAWN_ERR_PARAMCOUNT,
1720};
2629
2730#define PAWN_INST ((Pawn*) amx->userdata[0 ])
2831
29- constexpr int max_overlay_size = 512 ;
32+ constexpr int max_overlay_size = 2048 ;
3033
3134static void label_set_text (AMX* amx, lv_obj_t * label, cell str) {
3235 char * text;
@@ -464,10 +467,13 @@ static int AMXAPI prun_Overlay(AMX* amx, int index) {
464467 amx->code = (unsigned char *) amx_poolfind (&PAWN_INST->amx_pool , index);
465468
466469 if (amx->code == NULL ) {
470+ NRF_LOG_INFO (LOG_PREFIX " Reading overlay %d, %d bytes" , index, tbl->size );
471+
467472 if ((amx->code = (unsigned char *) amx_poolalloc (&PAWN_INST->amx_pool , tbl->size , index)) == NULL )
468473 return AMX_ERR_OVERLAY;
469474
470- memcpy (amx->code , PAWN_INST->file + hdr->cod + tbl->offset , tbl->size );
475+ if (PAWN_INST->file ->Read (amx->code , tbl->size , hdr->cod + tbl->offset ) < (size_t ) tbl->size )
476+ return PAWN_ERR_FILE;
471477 }
472478
473479 return AMX_ERR_NONE;
@@ -488,70 +494,81 @@ static int AMXAPI prun_Callback(struct tagAMX* amx, cell index, cell* result, co
488494}
489495
490496int Pawn::LoadProgram () {
497+ NRF_LOG_INFO (LOG_PREFIX " Loading program" );
498+
491499 int result;
492500 AMX_HEADER hdr;
493- memcpy (&hdr, file, sizeof (hdr));
501+ if (file->Read ((uint8_t *) &hdr, sizeof (hdr), 0 ) < sizeof (hdr))
502+ return PAWN_ERR_FILE;
494503
495504 if (hdr.magic != AMX_MAGIC)
496505 return AMX_ERR_FORMAT;
497506
498507 memset (&amx, 0 , sizeof (amx));
499508 amx.userdata [0 ] = this ;
500509
501- header = malloc (hdr.cod );
510+ header = std::make_unique< uint8_t []> (hdr.cod );
502511 if (header == NULL )
503512 return AMX_ERR_MEMORY;
504513
505- memcpy (header, file, hdr.cod );
514+ if (file->Read ((uint8_t *) header.get (), hdr.cod , 0 ) < (size_t ) hdr.cod )
515+ return PAWN_ERR_FILE;
506516
507- datablock = malloc (hdr.stp - hdr.dat ); // This block contains data, heap and stack
517+ datablock = std::make_unique< uint8_t []> (hdr.stp - hdr.dat ); // This block contains data, heap and stack
508518 if (datablock == NULL )
509519 return AMX_ERR_MEMORY;
510520
511- memcpy (datablock, file + hdr.dat , hdr.hea - hdr.dat );
512- amx.data = (unsigned char *) datablock;
521+ if (file->Read ((uint8_t *) datablock.get (), hdr.hea - hdr.dat , hdr.dat ) < (size_t ) hdr.hea - hdr.dat )
522+ return PAWN_ERR_FILE;
523+
524+ amx.data = (unsigned char *) datablock.get ();
513525
514526 if (hdr.flags & AMX_FLAG_OVERLAY) {
527+ NRF_LOG_INFO (LOG_PREFIX " Program has overlays" );
528+
515529 constexpr int overlaypool_overhead = 8 ;
516- overlaypool = malloc (max_overlay_size + overlaypool_overhead);
530+ overlaypool = std::make_unique< uint8_t []> (max_overlay_size + overlaypool_overhead);
517531 if (overlaypool == NULL )
518532 return AMX_ERR_MEMORY;
519533
520- amx_poolinit (&amx_pool, overlaypool, max_overlay_size + overlaypool_overhead);
534+ amx_poolinit (&amx_pool, overlaypool. get () , max_overlay_size + overlaypool_overhead);
521535
522536 amx.overlay = prun_Overlay;
523537
524- result = amx_Init (&amx, header);
525- if (result != AMX_ERR_NONE) {
526- free (header);
527- header = NULL ;
528- free (datablock);
529- datablock = NULL ;
530- free (overlaypool);
531- overlaypool = NULL ;
532- }
538+ result = amx_Init (&amx, header.get ());
533539 } else {
540+ NRF_LOG_INFO (LOG_PREFIX " Program doesn't have overlays" );
541+
534542 amx.flags |= AMX_FLAG_DSEG_INIT;
535543
536- result = amx_Init (&amx, (void *) file);
537- if (result != AMX_ERR_NONE) {
538- free (header);
539- header = NULL ;
540- free (datablock);
541- datablock = NULL ;
544+ // Happy path: the file is backed by a const array and we can reference it directly
545+ const uint8_t * code = file->GetConst ();
546+
547+ if (code == nullptr || true ) {
548+ // Slow path: we must read the whole file into memory
549+ NRF_LOG_INFO (LOG_PREFIX " Loading program into RAM" );
550+
551+ filecode = std::make_unique<uint8_t []>(hdr.size );
552+ if (file->Read (filecode.get (), hdr.size , 0 ) < (size_t ) hdr.size )
553+ return PAWN_ERR_FILE;
554+
555+ code = filecode.get ();
556+ } else {
557+ NRF_LOG_INFO (LOG_PREFIX " Loaded program from constant" )
542558 }
559+
560+ result = amx_Init (&amx, (void *) code);
543561 }
544562
545563 return result;
546564}
547565
548566#include " program.h"
549567
550- Pawn::Pawn (AppControllers& controllers) : Pawn(program, controllers) {
551- (void ) program_len;
568+ Pawn::Pawn (AppControllers& controllers) : Pawn(controllers, std::make_unique<LfsFile>(controllers.filesystem, " /flash.amx" )) {
552569}
553570
554- Pawn::Pawn (const uint8_t * file, AppControllers& controllers) : controllers(controllers), file(file) {
571+ Pawn::Pawn (AppControllers& controllers, std::unique_ptr<File> file ) : controllers(controllers), file(std::move( file) ) {
555572 int result = LoadProgram ();
556573 if (result != AMX_ERR_NONE) {
557574 ShowError (result);
@@ -604,13 +621,6 @@ Pawn::~Pawn() {
604621 CleanUI ();
605622
606623 amx_Cleanup (&amx);
607-
608- if (header)
609- free (header);
610- if (datablock)
611- free (datablock);
612- if (overlaypool)
613- free (overlaypool);
614624}
615625
616626void Pawn::Refresh () {
@@ -631,6 +641,8 @@ void Pawn::ShowError(unsigned int amx_err) {
631641 " missing event handler" , // PAWN_ERR_MISSINGHANDLER
632642 " invalid string" , // PAWN_ERR_INVALIDSTRING
633643 " invalid setting" , // PAWN_ERR_INVALIDSETTING
644+ " invalid trampoline" , // PAWN_ERR_INVALIDTRAMPOLINE
645+ " file read error" , // PAWN_ERR_FILE
634646 };
635647
636648 if (amx_err == AMX_ERR_EXIT) {
0 commit comments