@@ -4,6 +4,7 @@ package translate
44
55import (
66 "encoding/binary"
7+ "errors"
78 "math"
89 "net"
910 "time"
@@ -89,12 +90,16 @@ func (t FieldType) minLength() int {
8990 case Uint8 , Int8 , Boolean :
9091 return 1
9192 case Uint16 , Int16 :
92- return 2
93- case Uint32 , Int32 , Float32 , DateTimeSeconds :
93+ return 1
94+ case Uint32 , Int32 :
95+ return 1
96+ case Float32 , DateTimeSeconds :
9497 return 4
9598 case Uint64 , Int64 :
96- return 4 // NetFlow v9 encodes in both 4 and 8 bytes
97- case Float64 , DateTimeMilliseconds , DateTimeMicroseconds , DateTimeNanoseconds :
99+ return 1
100+ case Float64 :
101+ return 4 // Float64 can be encoded in 4 bytes though loss of precision may occur
102+ case DateTimeMilliseconds , DateTimeMicroseconds , DateTimeNanoseconds :
98103 return 8
99104 case MacAddress :
100105 return 6
@@ -129,6 +134,86 @@ type Key struct {
129134
130135type informationElements map [Key ]InformationElementEntry
131136
137+ var reducedSizeErr error = errors .New ("Unable to read reduced size encoding: size not implemented" )
138+ var tooManyBitsErr error = errors .New ("Unable to read reduced size encoding: too many bits" )
139+
140+ // Helper method to read an unsigned reduced size field
141+ func reducedSizeReadUnsigned (bs []byte , maxBits int ) (uint64 , error ) {
142+ // Exit if `bs` has more bits than we can store
143+ if len (bs )* 8 > maxBits {
144+ return 0 , tooManyBitsErr
145+ }
146+
147+ switch len (bs ) {
148+ case 1 :
149+ return uint64 (bs [0 ]), nil
150+ case 2 :
151+ return uint64 (binary .BigEndian .Uint16 (bs )), nil
152+ case 3 :
153+ return uint64 (uint32 (bs [0 ])<< 16 + uint32 (bs [1 ])<< 8 + uint32 (bs [2 ])), nil
154+ case 4 :
155+ return uint64 (binary .BigEndian .Uint32 (bs )), nil
156+ case 8 :
157+ return binary .BigEndian .Uint64 (bs ), nil
158+ }
159+ return 0 , reducedSizeErr
160+ }
161+
162+ // Helper method to read a signed reduced size field
163+ func reducedSizeReadSigned (bs []byte , maxBits int ) (int64 , error ) {
164+ // Exit if `bs` has more bits than we can store
165+ if len (bs )* 8 > maxBits {
166+ return 0 , tooManyBitsErr
167+ }
168+
169+ switch len (bs ) {
170+ case 1 :
171+ value := int8 (bs [0 ])
172+ return int64 (value ), nil
173+ case 2 :
174+ value := int16 (binary .BigEndian .Uint16 (bs ))
175+ return int64 (value ), nil
176+ case 4 :
177+ value := int32 (binary .BigEndian .Uint32 (bs ))
178+ return int64 (value ), nil
179+ case 8 :
180+ return int64 (binary .BigEndian .Uint64 (bs )), nil
181+ }
182+ return 0 , reducedSizeErr
183+ }
184+
185+ // Read a reduced size field into its full size
186+ func reducedSizeRead (bs []byte , i interface {}) error {
187+ var unsigned uint64
188+ var signed int64
189+ var err error
190+
191+ switch v := i .(type ) {
192+ case * uint16 :
193+ unsigned , err = reducedSizeReadUnsigned (bs , 16 )
194+ * v = uint16 (unsigned )
195+ case * uint32 :
196+ unsigned , err = reducedSizeReadUnsigned (bs , 32 )
197+ * v = uint32 (unsigned )
198+ case * uint64 :
199+ unsigned , err = reducedSizeReadUnsigned (bs , 64 )
200+ * v = uint64 (unsigned )
201+ case * int16 :
202+ signed , err = reducedSizeReadSigned (bs , 16 )
203+ * v = int16 (signed )
204+ case * int32 :
205+ signed , err = reducedSizeReadSigned (bs , 32 )
206+ * v = int32 (signed )
207+ case * int64 :
208+ signed , err = reducedSizeReadSigned (bs , 64 )
209+ * v = int64 (signed )
210+ default :
211+ err = reducedSizeErr
212+ }
213+
214+ return err
215+ }
216+
132217// Bytes translates a byte string to a go native type.
133218func Bytes (bs []byte , t FieldType ) interface {} {
134219 if len (bs ) < t .minLength () {
@@ -140,33 +225,46 @@ func Bytes(bs []byte, t FieldType) interface{} {
140225 case Uint8 :
141226 return bs [0 ]
142227 case Uint16 :
143- return binary .BigEndian .Uint16 (bs )
228+ var i uint16
229+ if err := reducedSizeRead (bs , & i ); err == nil {
230+ return i
231+ }
144232 case Uint32 :
145- return binary .BigEndian .Uint32 (bs )
233+ var i uint32
234+ if err := reducedSizeRead (bs , & i ); err == nil {
235+ return i
236+ }
146237 case Uint64 :
147- switch len (bs ) {
148- case 4 :
149- return uint64 (binary .BigEndian .Uint32 (bs ))
150- case 8 :
151- return binary .BigEndian .Uint64 (bs )
238+ var i uint64
239+ if err := reducedSizeRead (bs , & i ); err == nil {
240+ return i
152241 }
153242 case Int8 :
154243 return int8 (bs [0 ])
155244 case Int16 :
156- return int16 (binary .BigEndian .Uint16 (bs ))
245+ var i int16
246+ if err := reducedSizeRead (bs , & i ); err == nil {
247+ return i
248+ }
157249 case Int32 :
158- return int32 (binary .BigEndian .Uint32 (bs ))
250+ var i int32
251+ if err := reducedSizeRead (bs , & i ); err == nil {
252+ return i
253+ }
159254 case Int64 :
160- switch len (bs ) {
161- case 4 :
162- return int64 (binary .BigEndian .Uint32 (bs ))
163- case 8 :
164- return int64 (binary .BigEndian .Uint64 (bs ))
255+ var i int64
256+ if err := reducedSizeRead (bs , & i ); err == nil {
257+ return i
165258 }
166259 case Float32 :
167260 return math .Float32frombits (binary .BigEndian .Uint32 (bs ))
168261 case Float64 :
169- return math .Float64frombits (binary .BigEndian .Uint64 (bs ))
262+ switch len (bs ) {
263+ case 4 :
264+ return float64 (math .Float32frombits (binary .BigEndian .Uint32 (bs )))
265+ case 8 :
266+ return math .Float64frombits (binary .BigEndian .Uint64 (bs ))
267+ }
170268 case Boolean :
171269 return bs [0 ] == 1
172270 case Unknown , OctetArray :
0 commit comments