@@ -70,7 +70,7 @@ impl crate::Decoder for Decoder {
70
70
self . codec ( ) ,
71
71
)
72
72
} ) ?;
73
- ( value, * size as u64 )
73
+ ( value, * size)
74
74
} else {
75
75
let last = self . stack . pop ( ) . ok_or_else ( JerDecodeErrorKind :: eoi) ?;
76
76
let value_map = last
@@ -86,20 +86,26 @@ impl crate::Decoder for Decoder {
86
86
value_map
87
87
. get ( "length" )
88
88
. and_then ( |l| l. as_number ( ) )
89
- . and_then ( |i| i. as_u64 ( ) ) ,
89
+ . and_then ( |i| i. as_u64 ( ) )
90
+ . map ( |i| i as usize ) ,
90
91
)
91
92
. ok_or_else ( || JerDecodeErrorKind :: TypeMismatch {
92
93
needed : "JSON object containing 'value' and 'length' properties." ,
93
94
found : alloc:: format!( "{value_map:#?}" ) ,
94
95
} ) ?;
95
- (
96
- ( 0 ..value. len ( ) )
97
- . step_by ( 2 )
98
- . map ( |i| u8:: from_str_radix ( & value[ i..=i + 1 ] , 16 ) )
99
- . collect :: < Result < BitString , _ > > ( )
100
- . map_err ( |e| JerDecodeErrorKind :: InvalidJerBitstring { parse_int_err : e } ) ?,
101
- length,
102
- )
96
+
97
+ let value = bytes_from_hexstring ( value) . ok_or ( DecodeError :: custom (
98
+ alloc:: format!( "Failed to create BitString from bytes: {value:02x?}" ) ,
99
+ self . codec ( ) ,
100
+ ) ) ?;
101
+ let value = BitString :: try_from_vec ( value) . map_err ( |e| {
102
+ DecodeError :: custom (
103
+ alloc:: format!( "Failed to create BitString from bytes: {e:02x?}" ) ,
104
+ self . codec ( ) ,
105
+ )
106
+ } ) ?;
107
+
108
+ ( value, length)
103
109
} ;
104
110
let padding_length = if bitstring_length % 8 == 0 {
105
111
0
@@ -109,7 +115,15 @@ impl crate::Decoder for Decoder {
109
115
for _ in 0 ..padding_length {
110
116
padded. pop ( ) ;
111
117
}
112
- Ok ( padded)
118
+
119
+ if bitstring_length != padded. len ( ) {
120
+ Err ( DecodeError :: custom (
121
+ alloc:: format!( "Failed to create BitString from bytes: invalid value length (was: {}, expected: {})" , padded. len( ) , bitstring_length) ,
122
+ self . codec ( ) ,
123
+ ) )
124
+ } else {
125
+ Ok ( padded)
126
+ }
113
127
}
114
128
115
129
fn decode_bool ( & mut self , _t : Tag ) -> Result < bool , Self :: Error > {
@@ -605,11 +619,8 @@ impl Decoder {
605
619
needed : "hex string" ,
606
620
found : alloc:: format!( "{value}" ) ,
607
621
} ) ?;
608
- Ok ( ( 0 ..octet_string. len ( ) )
609
- . step_by ( 2 )
610
- . map ( |i| u8:: from_str_radix ( & octet_string[ i..=i + 1 ] , 16 ) )
611
- . collect :: < Result < alloc:: vec:: Vec < u8 > , _ > > ( )
612
- . map_err ( |_| JerDecodeErrorKind :: InvalidJerOctetString { } ) ?)
622
+ bytes_from_hexstring ( octet_string)
623
+ . ok_or ( JerDecodeErrorKind :: InvalidJerOctetString { } . into ( ) )
613
624
}
614
625
615
626
fn utc_time_from_value ( value : Value ) -> Result < chrono:: DateTime < chrono:: Utc > , DecodeError > {
@@ -647,3 +658,100 @@ impl Decoder {
647
658
} ) ?)
648
659
}
649
660
}
661
+
662
+ /// Parses a hex string into bytes.
663
+ fn bytes_from_hexstring ( hex_string : & str ) -> Option < alloc:: vec:: Vec < u8 > > {
664
+ if hex_string. len ( ) % 2 != 0 {
665
+ return None ;
666
+ }
667
+ let mut bytes = alloc:: vec:: Vec :: < u8 > :: with_capacity ( hex_string. len ( ) / 2 ) ;
668
+ for ( i, c) in hex_string. char_indices ( ) {
669
+ let n = nibble_from_hexdigit ( c) ?;
670
+ if i % 2 == 0 {
671
+ bytes. push ( n << 4 ) ;
672
+ } else {
673
+ bytes[ i / 2 ] |= n;
674
+ }
675
+ }
676
+ Some ( bytes)
677
+ }
678
+
679
+ /// Parses a hexdigit character into a nibble (four bits).
680
+ fn nibble_from_hexdigit ( c : char ) -> Option < u8 > {
681
+ match c {
682
+ '0' ..='9' => Some ( c as u8 - b'0' ) ,
683
+ 'a' ..='f' => Some ( c as u8 - b'a' + 0xA ) ,
684
+ 'A' ..='F' => Some ( c as u8 - b'A' + 0xA ) ,
685
+ _ => None ,
686
+ }
687
+ }
688
+
689
+ #[ cfg( test) ]
690
+ mod tests {
691
+ use super :: * ;
692
+
693
+ #[ test]
694
+ fn test_bytes_from_hexstring ( ) {
695
+ assert_eq ! ( bytes_from_hexstring( "" ) , Some ( vec![ ] ) ) ;
696
+ assert_eq ! ( bytes_from_hexstring( "00" ) , Some ( vec![ 0 ] ) ) ;
697
+ assert_eq ! ( bytes_from_hexstring( "FF" ) , Some ( vec![ 0xFF ] ) ) ;
698
+ assert_eq ! ( bytes_from_hexstring( "0000" ) , Some ( vec![ 0 , 0 ] ) ) ;
699
+ assert_eq ! ( bytes_from_hexstring( "FFFF" ) , Some ( vec![ 0xFF , 0xFF ] ) ) ;
700
+
701
+ assert_eq ! ( bytes_from_hexstring( " " ) , None ) ;
702
+ assert_eq ! ( bytes_from_hexstring( "!" ) , None ) ;
703
+ assert_eq ! ( bytes_from_hexstring( "0" ) , None ) ;
704
+ assert_eq ! ( bytes_from_hexstring( " 0" ) , None ) ;
705
+ assert_eq ! ( bytes_from_hexstring( "0 " ) , None ) ;
706
+ assert_eq ! ( bytes_from_hexstring( "0!" ) , None ) ;
707
+ assert_eq ! ( bytes_from_hexstring( " " ) , None ) ;
708
+ assert_eq ! ( bytes_from_hexstring( "00 " ) , None ) ;
709
+ assert_eq ! ( bytes_from_hexstring( " 00" ) , None ) ;
710
+ assert_eq ! ( bytes_from_hexstring( "000" ) , None ) ;
711
+ assert_eq ! ( bytes_from_hexstring( "Œ" ) , None ) ;
712
+ assert_eq ! ( bytes_from_hexstring( "ŒŒ" ) , None ) ;
713
+ assert_eq ! ( bytes_from_hexstring( "ŒŒŒ" ) , None ) ;
714
+ assert_eq ! ( bytes_from_hexstring( "ABCDEFG" ) , None ) ;
715
+ assert_eq ! ( bytes_from_hexstring( " ABCDEF" ) , None ) ;
716
+ assert_eq ! ( bytes_from_hexstring( "\u{0000} " ) , None ) ;
717
+ assert_eq ! ( bytes_from_hexstring( "\u{FFFF} " ) , None ) ;
718
+ assert_eq ! ( bytes_from_hexstring( "\u{0123} " ) , None ) ;
719
+ assert_eq ! ( bytes_from_hexstring( "\u{30} " ) , None ) ;
720
+ assert_eq ! ( bytes_from_hexstring( "\\ u0030" ) , None ) ;
721
+ assert_eq ! ( bytes_from_hexstring( "\\ u202E\\ u0030\\ u0030" ) , None ) ;
722
+ assert_eq ! ( bytes_from_hexstring( "⣐⡄" ) , None ) ;
723
+ assert_eq ! ( bytes_from_hexstring( "😎" ) , None ) ;
724
+ assert_eq ! ( bytes_from_hexstring( "🙈🙉🙊" ) , None ) ;
725
+ }
726
+
727
+ #[ test]
728
+ fn test_nibble_from_hexdigit ( ) {
729
+ for c in '\u{0}' ..'\u{1024}' {
730
+ match c {
731
+ '0' => assert_eq ! ( Some ( 0x00 ) , nibble_from_hexdigit( c) ) ,
732
+ '1' => assert_eq ! ( Some ( 0x01 ) , nibble_from_hexdigit( c) ) ,
733
+ '2' => assert_eq ! ( Some ( 0x02 ) , nibble_from_hexdigit( c) ) ,
734
+ '3' => assert_eq ! ( Some ( 0x03 ) , nibble_from_hexdigit( c) ) ,
735
+ '4' => assert_eq ! ( Some ( 0x04 ) , nibble_from_hexdigit( c) ) ,
736
+ '5' => assert_eq ! ( Some ( 0x05 ) , nibble_from_hexdigit( c) ) ,
737
+ '6' => assert_eq ! ( Some ( 0x06 ) , nibble_from_hexdigit( c) ) ,
738
+ '7' => assert_eq ! ( Some ( 0x07 ) , nibble_from_hexdigit( c) ) ,
739
+ '8' => assert_eq ! ( Some ( 0x08 ) , nibble_from_hexdigit( c) ) ,
740
+ '9' => assert_eq ! ( Some ( 0x09 ) , nibble_from_hexdigit( c) ) ,
741
+ 'A' => assert_eq ! ( Some ( 0x0A ) , nibble_from_hexdigit( c) ) ,
742
+ 'B' => assert_eq ! ( Some ( 0x0B ) , nibble_from_hexdigit( c) ) ,
743
+ 'C' => assert_eq ! ( Some ( 0x0C ) , nibble_from_hexdigit( c) ) ,
744
+ 'D' => assert_eq ! ( Some ( 0x0D ) , nibble_from_hexdigit( c) ) ,
745
+ 'E' => assert_eq ! ( Some ( 0x0E ) , nibble_from_hexdigit( c) ) ,
746
+ 'F' => assert_eq ! ( Some ( 0x0F ) , nibble_from_hexdigit( c) ) ,
747
+ 'a' => assert_eq ! ( Some ( 0x0A ) , nibble_from_hexdigit( c) ) ,
748
+ 'b' => assert_eq ! ( Some ( 0x0B ) , nibble_from_hexdigit( c) ) ,
749
+ 'c' => assert_eq ! ( Some ( 0x0C ) , nibble_from_hexdigit( c) ) ,
750
+ 'd' => assert_eq ! ( Some ( 0x0D ) , nibble_from_hexdigit( c) ) ,
751
+ 'e' => assert_eq ! ( Some ( 0x0E ) , nibble_from_hexdigit( c) ) ,
752
+ 'f' => assert_eq ! ( Some ( 0x0F ) , nibble_from_hexdigit( c) ) ,
753
+ _ => assert_eq ! ( None , nibble_from_hexdigit( c) ) ,
754
+ }
755
+ }
756
+ }
757
+ }
0 commit comments