@@ -978,11 +978,11 @@ export class Parser {
978978 this . generateWrapper ( ctx ) ;
979979 break ;
980980 }
981- this . generateAssert ( ctx ) ;
981+ if ( this . type !== "bit" ) this . generateAssert ( ctx ) ;
982982 }
983983
984984 const varName = ctx . generateVariable ( this . varName ) ;
985- if ( this . options . formatter ) {
985+ if ( this . options . formatter && this . type !== "bit" ) {
986986 this . generateFormatter ( ctx , varName , this . options . formatter ) ;
987987 }
988988
@@ -1036,53 +1036,99 @@ export class Parser {
10361036 private generateBit ( ctx : Context ) {
10371037 // TODO find better method to handle nested bit fields
10381038 const parser = JSON . parse ( JSON . stringify ( this ) ) ;
1039+ parser . options = this . options ;
1040+ parser . generateAssert = this . generateAssert . bind ( this ) ;
1041+ parser . generateFormatter = this . generateFormatter . bind ( this ) ;
10391042 parser . varName = ctx . generateVariable ( parser . varName ) ;
10401043 ctx . bitFields . push ( parser ) ;
10411044
10421045 if (
10431046 ! this . next ||
10441047 ( this . next && [ "bit" , "nest" ] . indexOf ( this . next . type ) < 0 )
10451048 ) {
1046- let sum = 0 ;
1047- ctx . bitFields . forEach (
1048- ( parser ) => ( sum += parser . options . length as number )
1049- ) ;
1050-
10511049 const val = ctx . generateTmpVariable ( ) ;
10521050
1053- if ( sum <= 8 ) {
1054- ctx . pushCode ( `var ${ val } = dataView.getUint8(offset);` ) ;
1055- sum = 8 ;
1056- } else if ( sum <= 16 ) {
1057- ctx . pushCode ( `var ${ val } = dataView.getUint16(offset);` ) ;
1058- sum = 16 ;
1059- } else if ( sum <= 24 ) {
1060- const val1 = ctx . generateTmpVariable ( ) ;
1061- const val2 = ctx . generateTmpVariable ( ) ;
1062- ctx . pushCode ( `var ${ val1 } = dataView.getUint16(offset);` ) ;
1063- ctx . pushCode ( `var ${ val2 } = dataView.getUint8(offset + 2);` ) ;
1064- ctx . pushCode ( `var ${ val } = (${ val1 } << 8) | ${ val2 } ;` ) ;
1065- sum = 24 ;
1066- } else if ( sum <= 32 ) {
1067- ctx . pushCode ( `var ${ val } = dataView.getUint32(offset);` ) ;
1068- sum = 32 ;
1069- } else {
1070- throw new Error (
1071- "Currently, bit field sequence longer than 4-bytes is not supported."
1072- ) ;
1073- }
1074- ctx . pushCode ( `offset += ${ sum / 8 } ;` ) ;
1051+ ctx . pushCode ( `var ${ val } = 0;` ) ;
1052+
1053+ const getMaxBits = ( from = 0 ) => {
1054+ let sum = 0 ;
1055+ for ( let i = from ; i < ctx . bitFields . length ; i ++ ) {
1056+ const length = ctx . bitFields [ i ] . options . length as number ;
1057+ if ( sum + length > 32 ) break ;
1058+ sum += length ;
1059+ }
1060+ return sum ;
1061+ } ;
1062+
1063+ const getBytes = ( sum : number ) => {
1064+ if ( sum <= 8 ) {
1065+ ctx . pushCode ( `${ val } = dataView.getUint8(offset);` ) ;
1066+ sum = 8 ;
1067+ } else if ( sum <= 16 ) {
1068+ ctx . pushCode ( `${ val } = dataView.getUint16(offset);` ) ;
1069+ sum = 16 ;
1070+ } else if ( sum <= 24 ) {
1071+ ctx . pushCode (
1072+ `${ val } = (dataView.getUint16(offset) << 8) | dataView.getUint8(offset + 2);`
1073+ ) ;
1074+ sum = 24 ;
1075+ } else {
1076+ ctx . pushCode ( `${ val } = dataView.getUint32(offset);` ) ;
1077+ sum = 32 ;
1078+ }
1079+ ctx . pushCode ( `offset += ${ sum / 8 } ;` ) ;
1080+ return sum ;
1081+ } ;
10751082
10761083 let bitOffset = 0 ;
10771084 const isBigEndian = this . endian === "be" ;
10781085
1079- ctx . bitFields . forEach ( ( parser ) => {
1080- const length = parser . options . length as number ;
1086+ let sum = 0 ;
1087+ let rem = 0 ;
1088+
1089+ ctx . bitFields . forEach ( ( parser , i ) => {
1090+ let length = parser . options . length as number ;
1091+ if ( length > rem ) {
1092+ if ( rem ) {
1093+ const mask = - 1 >>> ( 32 - rem ) ;
1094+ ctx . pushCode (
1095+ `${ parser . varName } = (${ val } & 0x${ mask . toString ( 16 ) } ) << ${
1096+ length - rem
1097+ } ;`
1098+ ) ;
1099+ length -= rem ;
1100+ }
1101+ bitOffset = 0 ;
1102+ rem = sum = getBytes ( getMaxBits ( i ) - rem ) ;
1103+ }
10811104 const offset = isBigEndian ? sum - bitOffset - length : bitOffset ;
1082- const mask = ( 1 << length ) - 1 ;
1105+ const mask = - 1 >>> ( 32 - length ) ;
1106+
1107+ ctx . pushCode (
1108+ `${ parser . varName } ${
1109+ length < ( parser . options . length as number ) ? "|=" : "="
1110+ } ${ val } >> ${ offset } & 0x${ mask . toString ( 16 ) } ;`
1111+ ) ;
1112+
1113+ // Ensure value is unsigned
1114+ if ( ( parser . options . length as number ) === 32 ) {
1115+ ctx . pushCode ( `${ parser . varName } >>>= 0` ) ;
1116+ }
1117+
1118+ if ( parser . options . assert ) {
1119+ parser . generateAssert ( ctx ) ;
1120+ }
1121+
1122+ if ( parser . options . formatter ) {
1123+ parser . generateFormatter (
1124+ ctx ,
1125+ parser . varName ,
1126+ parser . options . formatter
1127+ ) ;
1128+ }
10831129
1084- ctx . pushCode ( `${ parser . varName } = ${ val } >> ${ offset } & ${ mask } ;` ) ;
10851130 bitOffset += length ;
1131+ rem -= length ;
10861132 } ) ;
10871133
10881134 ctx . bitFields = [ ] ;
0 commit comments