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  }