From 528257705d0c6198bd773f8bf87a44937f9810be Mon Sep 17 00:00:00 2001 From: mikecarper Date: Wed, 30 Sep 2026 04:00:04 -0700 Subject: [PATCH] Reject octave formats misread by the installed buzzer parser --- src/helpers/CompanionNotificationPolicy.h | 11 ++++++++--- .../test_companion_notifications.cpp | 4 +++- test/test_notification_builder.js | 3 ++- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/src/helpers/CompanionNotificationPolicy.h b/src/helpers/CompanionNotificationPolicy.h index 881c004a..bc46060b 100644 --- a/src/helpers/CompanionNotificationPolicy.h +++ b/src/helpers/CompanionNotificationPolicy.h @@ -79,19 +79,24 @@ inline bool soundDuration(const char* p,uint32_t& total) { while(*p && *p!=':') { if(!((*p>='a'&&*p<='z')||(*p>='A'&&*p<='Z')||(*p>='0'&&*p<='9')||*p=='_')||++name>12) return false; ++p; } if(!name||*p++!=':'||strncmp(p,"d=",2)) return false; p+=2; uint32_t d,o,b; - if(!number(p,d,32)||!durationDenominator(d)||*p++!=','||strncmp(p,"o=",2)) return false; + if(*p=='0'||!number(p,d,32)||!durationDenominator(d)||*p++!=','||strncmp(p,"o=",2)) return false; p+=2; - if(!number(p,o,7)||o<4||*p++!=','||strncmp(p,"b=",2)) return false; + // The installed driver consumes exactly one octave digit, unlike duration + // and BPM. Accepting c04 would send octave 0 into its pitch-table index. + if(*p<'4'||*p>'7')return false; + o=*p++-'0'; + if(*p++!=','||strncmp(p,"b=",2)) return false; p+=2; if(!number(p,b,900)||b<25||*p++!=':'||!*p) return false; do { uint32_t nd=d,no=o; + if(*p=='0')return false; if(*p>='0'&&*p<='9' && (!number(p,nd,32)||!durationDenominator(nd))) return false; char note=*p++; if((note<'a'||note>'g')&¬e!='p') return false; if(*p=='#') { if(note!='a'&¬e!='c'&¬e!='d'&¬e!='f'&¬e!='g') return false; ++p; } bool dot=*p=='.'; if(dot) ++p; - if(*p>='0'&&*p<='9' && (!number(p,no,7)||no<4)) return false; + if(*p>='0'&&*p<='9') { no=*p++-'0';if(no<4||no>7)return false; } if(*p=='.') { if(dot) return false; dot=true; ++p; } uint32_t ms=(60000/b)*4/nd; if(dot) ms+=ms/2; total+=ms; diff --git a/test/test_companion_notifications/test_companion_notifications.cpp b/test/test_companion_notifications/test_companion_notifications.cpp index c9376853..80628d9a 100644 --- a/test/test_companion_notifications/test_companion_notifications.cpp +++ b/test/test_companion_notifications/test_companion_notifications.cpp @@ -43,7 +43,9 @@ TEST(NotificationParsing, ValidatesTheActualBuzzerTableAndRtttlSyntax) { for(auto text:{"abc","x:d=8,o=3,b=120:c","x:d=8,o=5,b=0:c","x:d=8,o=8,b=120:c", "x:d=3,o=5,b=120:c","x:d=8,o=5,b=120:b#7","x:d=8,o=5,b=120:c,", "x:d=8,o=5,b=120:c..","x:d=8,o=5,b=120:c8","x:d=8,o=5,b=120:p#", - "x:d=8,o=5,b=120:c+","x:d=8,o=5,b=120:c, d"})EXPECT_FALSE(soundDuration(text,ms))< builder.pulse(bad)); assert.equal(builder.melody("vip:d=8,o=5,b=120:c,c#,16p,4g.6").length, 4); for (const bad of ["abc", "x:d=8,o=3,b=120:c", "x:d=8,o=5,b=0:c", "x:d=3,o=5,b=120:c", - "x:d=8,o=5,b=120:b#7", "x:d=8,o=5,b=120:c,", "x:d=8,o=5,b=120:c..", "x:d=8,o=5,b=120:p#"]) + "x:d=8,o=5,b=120:b#7", "x:d=8,o=5,b=120:c,", "x:d=8,o=5,b=120:c..", "x:d=8,o=5,b=120:p#", + "x:d=8,o=04,b=120:c", "x:d=8,o=5,b=120:c04", "x:d=8,o=5,b=120:c007", "x:d=08,o=5,b=120:c", "x:d=8,o=5,b=120:04c"]) assert.throws(() => builder.melody(bad)); for (const config of Object.values(builder.EXAMPLES)) { const complete = {...config, id: config.kind === "contact" ? "01".repeat(32) : config.id};