@@ -580,11 +580,14 @@ function parseMemoryRecord(line: string): NuVoiceMemoryRecord {
580580 throw new Error ( `Invalid NuVoice memory record: ${ line } ` ) ;
581581 }
582582
583- const markerLength = 4 ;
584- const pageBytes = base . bodyBytes . slice ( 1 , 3 ) ;
585- const sequence = base . bodyBytes [ 3 ] ;
586- const payloadBytes = base . bodyBytes . slice ( markerLength ) ;
587- const parsedButton = parseNuVoiceButtonPayload ( base . bodyBytes ) ;
583+ const fullBytes = new Uint8Array ( base . bodyBytes . length + 1 ) ;
584+ fullBytes [ 0 ] = 0x6d ;
585+ fullBytes . set ( base . bodyBytes , 1 ) ;
586+
587+ const pageBytes = fullBytes . slice ( 4 , 6 ) ;
588+ const sequence = fullBytes [ 6 ] ;
589+ const payloadBytes = base . bodyBytes . slice ( 6 ) ;
590+ const parsedButton = parseNuVoiceButtonPayload ( fullBytes ) ;
588591 return {
589592 ...base ,
590593 type : 'm' ,
@@ -611,40 +614,42 @@ function textFromRecordBody(type: string, bodyBytes: Uint8Array): string | undef
611614 return `${ type } ${ bytesToLatin1 ( bodyBytes ) } ` ;
612615}
613616
614- function parseNuVoiceButtonPayload ( bodyBytes : Uint8Array ) : NuVoiceButtonData | undefined {
615- if ( bodyBytes . length < 14 ) {
617+ function parseNuVoiceButtonPayload ( fullBytes : Uint8Array ) : NuVoiceButtonData | undefined {
618+ if ( fullBytes . length < 14 || fullBytes [ 0 ] !== 0x6d ) {
616619 return undefined ;
617620 }
618- const formatMarker = bodyBytes [ 9 ] ;
621+ const formatMarker = fullBytes [ 9 ] ;
619622 if ( formatMarker >= 1 && formatMarker <= 49 ) {
620- return parseNuVoiceFormat1 ( bodyBytes , formatMarker ) ;
623+ return parseNuVoiceFormat1 ( fullBytes , formatMarker ) ;
621624 }
622625 if ( formatMarker === 0 ) {
623- return parseNuVoiceFormat2 ( bodyBytes ) ;
626+ return parseNuVoiceFormat2 ( fullBytes ) ;
624627 }
625- if ( [ 0x87 , 0xaf , 0xcc , 0xff , 0xf5 , 0xf0 ] . includes ( formatMarker ) ) {
626- return parseNuVoiceFormat5 ( bodyBytes ) ;
628+ if ( [ 0x87 , 0xaf , 0xcc , 0xff ] . includes ( formatMarker ) ) {
629+ return parseNuVoiceFormat5 ( fullBytes ) ;
627630 }
628631 return undefined ;
629632}
630633
631- function parseNuVoiceFormat1 ( bodyBytes : Uint8Array , nameLength : number ) : NuVoiceButtonData {
634+ function parseNuVoiceFormat1 ( fullBytes : Uint8Array , nameLength : number ) : NuVoiceButtonData {
632635 let cursor = 10 ;
633- const end = Math . min ( cursor + nameLength , bodyBytes . length ) ;
634- const name = bytesToLatin1 ( bodyBytes . slice ( cursor , end ) ) . trim ( ) ;
636+ const end = Math . min ( cursor + nameLength , fullBytes . length ) ;
637+ const name = bytesToLatin1 ( fullBytes . slice ( cursor , end ) ) . trim ( ) ;
635638 cursor = end ;
636- if ( cursor < bodyBytes . length && bodyBytes [ cursor ] === 0 ) {
639+ if ( cursor < fullBytes . length && fullBytes [ cursor ] === 0 ) {
637640 cursor += 1 ;
638641 }
639- let icon = undefined ;
640- if ( cursor < bodyBytes . length ) {
641- const iconLength = bodyBytes [ cursor ] ;
642+ let icon : string | undefined ;
643+ if ( cursor < fullBytes . length ) {
644+ const iconLength = fullBytes [ cursor ] ;
642645 cursor += 1 ;
643- icon = bytesToLatin1 ( bodyBytes . slice ( cursor , cursor + iconLength ) ) . trim ( ) ;
644- cursor += iconLength ;
646+ if ( iconLength > 0 && cursor + iconLength <= fullBytes . length ) {
647+ icon = bytesToLatin1 ( fullBytes . slice ( cursor , cursor + iconLength ) ) . trim ( ) ;
648+ cursor += iconLength ;
649+ }
645650 }
646651 const { speech, navigationType, navigationTarget, functions, randomChoiceTarget } =
647- parseNuVoiceFunctions ( bodyBytes . slice ( cursor ) ) ;
652+ parseNuVoiceFunctions ( fullBytes . slice ( cursor ) ) ;
648653 return {
649654 name,
650655 icon,
@@ -656,32 +661,44 @@ function parseNuVoiceFormat1(bodyBytes: Uint8Array, nameLength: number): NuVoice
656661 } ;
657662}
658663
659- function parseNuVoiceFormat2 ( bodyBytes : Uint8Array ) : NuVoiceButtonData {
660- let text = bytesToLatin1 ( bodyBytes . slice ( 11 ) ) ;
661- while ( text . endsWith ( '\u0000' ) ) {
662- text = text . slice ( 0 , - 1 ) ;
664+ function parseNuVoiceFormat2 ( fullBytes : Uint8Array ) : NuVoiceButtonData {
665+ let cursor = 10 ;
666+ while ( cursor < fullBytes . length && fullBytes [ cursor ] === 0 ) {
667+ cursor += 1 ;
668+ }
669+ let end = cursor ;
670+ while ( end + 1 < fullBytes . length ) {
671+ if ( fullBytes [ end ] === 0x0d && fullBytes [ end + 1 ] === 0x0a ) {
672+ break ;
673+ }
674+ end += 1 ;
663675 }
664- text = text . trim ( ) ;
676+ let textBytes = fullBytes . slice ( cursor , end ) ;
677+ textBytes = textBytes . filter ( ( value ) => value >= 0x20 ) ;
678+ const text = bytesToLatin1 ( textBytes ) . trim ( ) ;
665679 return { name : text , speech : text , functions : [ ] } ;
666680}
667681
668- function parseNuVoiceFormat5 ( bodyBytes : Uint8Array ) : NuVoiceButtonData | undefined {
669- if ( bodyBytes . length < 14 ) {
682+ function parseNuVoiceFormat5 ( fullBytes : Uint8Array ) : NuVoiceButtonData | undefined {
683+ if ( fullBytes . length < 14 ) {
670684 return undefined ;
671685 }
672- const nameLength = bodyBytes [ 13 ] ;
686+ const nameLength = fullBytes [ 13 ] ;
673687 let cursor = 14 ;
674- const name = bytesToLatin1 ( bodyBytes . slice ( cursor , cursor + nameLength ) ) . trim ( ) ;
688+ const name = bytesToLatin1 ( fullBytes . slice ( cursor , cursor + nameLength ) ) . trim ( ) ;
675689 cursor += nameLength ;
676- if ( cursor < bodyBytes . length && bodyBytes [ cursor ] === 0 ) {
690+ if ( cursor < fullBytes . length && fullBytes [ cursor ] === 0 ) {
677691 cursor += 1 ;
678692 }
679- const iconLength = bodyBytes [ cursor ] ?? 0 ;
680- cursor += 1 ;
681- const icon = bytesToLatin1 ( bodyBytes . slice ( cursor , cursor + iconLength ) ) . trim ( ) ;
682- cursor += iconLength ;
693+ let icon : string | undefined ;
694+ if ( cursor < fullBytes . length ) {
695+ const iconLength = fullBytes [ cursor ] ?? 0 ;
696+ cursor += 1 ;
697+ icon = bytesToLatin1 ( fullBytes . slice ( cursor , cursor + iconLength ) ) . trim ( ) ;
698+ cursor += iconLength ;
699+ }
683700 const { speech, navigationType, navigationTarget, functions, randomChoiceTarget } =
684- parseNuVoiceFunctions ( bodyBytes . slice ( cursor ) ) ;
701+ parseNuVoiceFunctions ( fullBytes . slice ( cursor ) ) ;
685702 return {
686703 name,
687704 icon,
0 commit comments