1818package codec
1919
2020import (
21+ "encoding/hex"
2122 "errors"
2223 "fmt"
2324 "io"
@@ -71,8 +72,6 @@ const (
7172)
7273
7374func (c * Comp3 ) Decode (buffer api.Buffer , offset int ) (any , error ) {
74- result := & strings.Builder {}
75-
7675 bytes , err := buffer .Slice (offset , c .size )
7776 if err != nil && ! errors .Is (err , io .EOF ) {
7877 return nil , fmt .Errorf ("%w" , err ) // return error if buffer is too short
@@ -82,33 +81,35 @@ func (c *Comp3) Decode(buffer api.Buffer, offset int) (any, error) {
8281 return "" , nil
8382 }
8483
84+ return c .decode (bytes )
85+ }
86+
87+ func (c * Comp3 ) decode (bytes []byte ) (string , error ) {
88+ result := make ([]rune , 0 , c .length )
89+
8590 for byteIndex , byteVal := range bytes {
86- if byteIndex * 2 == c .intDigits {
87- result . WriteRune ( c .sep )
91+ if byteIndex * 2 == c .intDigits && c . decDigits > 0 {
92+ result = append ( result , c .sep )
8893 }
8994
9095 if byteIndex == c .size - 1 {
91- high := (byteVal & highNibbleMask ) >> nibbleShift
92-
9396 if byteIndex * 2 < c .intDigits + c .decDigits {
94- result . WriteRune ( convertNibbleToRune ( high ))
97+ result = append ( result , convertHighNibbleToRune ( byteVal ))
9598 }
9699
97- sign := handleSign (byteVal )
98-
99- return sign + result .String (), nil
100+ return handleSign (string (result ), byteVal , bytes ), nil
100101 }
101102
102- result . WriteRune ( convertNibbleToRune (( byteVal & highNibbleMask ) >> nibbleShift ))
103+ result = append ( result , convertHighNibbleToRune ( byteVal ))
103104
104- if byteIndex * 2 + 1 == c .intDigits {
105- result . WriteRune ( c .sep )
105+ if byteIndex * 2 + 1 == c .intDigits && c . decDigits > 0 {
106+ result = append ( result , c .sep )
106107 }
107108
108- result . WriteRune ( convertNibbleToRune (byteVal & lowNibbleMask ))
109+ result = append ( result , convertLowNibbleToRune (byteVal ))
109110 }
110111
111- return result . String ( ), ErrBufferTooShort // should never happen because short buffer is handled by buffer interface
112+ return string ( result ), ErrBufferTooShort // should never happen because short buffer is handled by buffer interface
112113}
113114
114115func (c * Comp3 ) Encode (buffer api.Buffer , offset int , value any ) error {
@@ -121,6 +122,14 @@ func (c *Comp3) Encode(buffer api.Buffer, offset int, value any) error {
121122 return nil
122123 }
123124
125+ if bytes := c .detectInvalidBuffer (value ); bytes != nil {
126+ if err := buffer .Write (offset , bytes ); err != nil {
127+ return fmt .Errorf ("%w" , err )
128+ }
129+
130+ return nil
131+ }
132+
124133 nibbleSign , str , err := c .detectSignAndAddLeadingZeroes (value )
125134 if err != nil {
126135 return err
@@ -140,6 +149,28 @@ func (c *Comp3) Encode(buffer api.Buffer, offset int, value any) error {
140149 return c .encode (buffer , offset , str , nibbleSign )
141150}
142151
152+ func (c * Comp3 ) detectInvalidBuffer (value any ) []byte {
153+ str , ok := value .(string )
154+ if ! ok {
155+ return nil
156+ }
157+
158+ if len (str ) == 0 {
159+ return nil
160+ }
161+
162+ if str [0 ] == '!' {
163+ bytes , err := hex .DecodeString (str [1 :])
164+ if err != nil {
165+ return nil
166+ }
167+
168+ return bytes
169+ }
170+
171+ return nil
172+ }
173+
143174func (c * Comp3 ) detectSignAndAddLeadingZeroes (value any ) (byte , string , error ) {
144175 str , ok := value .(string )
145176 if ! ok {
@@ -236,6 +267,14 @@ const (
236267 alphaNibbleOffset = 10
237268)
238269
270+ func convertHighNibbleToRune (byteVal byte ) rune {
271+ return convertNibbleToRune ((byteVal & highNibbleMask ) >> nibbleShift )
272+ }
273+
274+ func convertLowNibbleToRune (byteVal byte ) rune {
275+ return convertNibbleToRune (byteVal & lowNibbleMask )
276+ }
277+
239278func convertNibbleToRune (nibble byte ) rune {
240279 if nibble <= maxDecimalNibble {
241280 return rune ('0' + nibble )
@@ -260,21 +299,20 @@ func convertRuneToNibble(runeVal rune) (byte, error) {
260299 return 0 , fmt .Errorf ("%w: invalid rune %q" , ErrInvalidComp3Nibble , runeVal )
261300}
262301
263- func handleSign (byteVal byte ) string {
302+ func handleSign (result string , byteVal byte , buffer [] byte ) string {
264303 signNibble := byteVal & lowNibbleMask
265304
266- if signNibble != signNibblePositive && signNibble != signNibbleNegative && signNibble != signNibbleZero {
267- return "#"
268- }
269-
270305 switch signNibble {
271306 case signNibbleNegative :
272- return "-"
307+ return "-" + result
273308 case signNibblePositive :
274- return "+"
309+ return "+" + result
310+ case signNibbleZero :
311+ return result
275312 }
276313
277- return ""
314+ // return buffer value as hex string in case of invalid sign nibble
315+ return "!" + hex .EncodeToString (buffer )
278316}
279317
280318func isNull (bytes []byte ) bool {
0 commit comments