github.phpd.cn/cilium/cilium@v1.6.12/pkg/byteorder/byteorder.go (about) 1 // Copyright 2017 Authors of Cilium 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package byteorder 16 17 import ( 18 "encoding/binary" 19 "fmt" 20 "reflect" 21 "unsafe" 22 ) 23 24 // Native is set to the host ByteOrder type. This should normally be either 25 // BigEndian or LittleEndian. 26 var Native = getNativeEndian() 27 var nativeEndian binary.ByteOrder 28 29 func getNativeEndian() binary.ByteOrder { 30 if nativeEndian == nil { 31 var x uint32 = 0x01020304 32 if *(*byte)(unsafe.Pointer(&x)) == 0x01 { 33 nativeEndian = binary.BigEndian 34 } else { 35 nativeEndian = binary.LittleEndian 36 } 37 } 38 return nativeEndian 39 } 40 41 // Byte swap a 16 bit value if we aren't big endian 42 func swap16(i uint16) uint16 { 43 if Native == binary.BigEndian { 44 return i 45 } 46 return (i&0xff00)>>8 | (i&0xff)<<8 47 } 48 49 // Byte swap a 32 bit value if aren't big endian 50 func swap32(i uint32) uint32 { 51 if Native == binary.BigEndian { 52 return i 53 } 54 return (i&0xff000000)>>24 | (i&0xff0000)>>8 | (i&0xff00)<<8 | (i&0xff)<<24 55 } 56 57 // reverse returns a reversed slice of b. 58 func reverse(b []byte) []byte { 59 size := len(b) 60 c := make([]byte, size) 61 62 for i, j := size-1, 0; i >= 0; i, j = i-1, j+1 { 63 c[j] = b[i] 64 } 65 66 return c 67 } 68 69 // HostToNetwork converts b to the networking byte order. 70 func HostToNetwork(b interface{}) interface{} { 71 switch b.(type) { 72 case uint16: 73 return swap16(b.(uint16)) 74 case uint32: 75 return swap32(b.(uint32)) 76 default: 77 panic(unsupported(b)) 78 } 79 } 80 81 // NetworkToHost converts n to host byte order. 82 func NetworkToHost(n interface{}) interface{} { 83 switch n.(type) { 84 case uint16: 85 return swap16(n.(uint16)) 86 case uint32: 87 return swap32(n.(uint32)) 88 default: 89 panic(unsupported(n)) 90 } 91 } 92 93 // HostToNetworkSlice converts b to the networking byte order. 94 func HostToNetworkSlice(b []byte, t reflect.Kind) interface{} { 95 switch t { 96 case reflect.Uint32: 97 return binary.BigEndian.Uint32(b) 98 case reflect.Uint16: 99 return binary.BigEndian.Uint16(b) 100 default: 101 panic(unsupported(b)) 102 } 103 } 104 105 // HostToNetworkPut puts v into b with the networking byte order. 106 func HostToNetworkPut(b []byte, v interface{}) { 107 switch reflect.TypeOf(v).Kind() { 108 case reflect.Uint32: 109 binary.BigEndian.PutUint32(b, v.(uint32)) 110 case reflect.Uint16: 111 binary.BigEndian.PutUint16(b, v.(uint16)) 112 default: 113 panic(unsupported(v)) 114 } 115 } 116 117 // NetworkToHostPut puts v into b with the networking byte order. 118 func NetworkToHostPut(b []byte, v interface{}) { 119 switch reflect.TypeOf(v).Kind() { 120 case reflect.Uint32: 121 Native.PutUint32(b, v.(uint32)) 122 case reflect.Uint16: 123 Native.PutUint16(b, v.(uint16)) 124 default: 125 panic(unsupported(v)) 126 } 127 } 128 129 // HostSliceToNetwork converts b to the networking byte order. 130 func HostSliceToNetwork(b []byte, t reflect.Kind) interface{} { 131 switch t { 132 case reflect.Uint32: 133 if Native != binary.BigEndian { 134 return binary.BigEndian.Uint32(reverse(b)) 135 } 136 return binary.BigEndian.Uint32(b) 137 case reflect.Uint16: 138 if Native != binary.BigEndian { 139 return binary.BigEndian.Uint16(reverse(b)) 140 } 141 return binary.BigEndian.Uint16(b) 142 default: 143 panic(unsupported(t)) 144 } 145 } 146 147 // unsupported returns a string to used for debugging unhandled types. 148 func unsupported(field interface{}) string { 149 return fmt.Sprintf("unsupported type(%v): %v", reflect.TypeOf(field).Kind(), field) 150 }