1package danger
2
3import (
4	"fmt"
5	"reflect"
6	"unsafe"
7)
8
9const maxInt = uintptr(int(^uint(0) >> 1))
10
11func SubsliceOffset(data []byte, subslice []byte) int {
12	datap := (*reflect.SliceHeader)(unsafe.Pointer(&data))
13	hlp := (*reflect.SliceHeader)(unsafe.Pointer(&subslice))
14
15	if hlp.Data < datap.Data {
16		panic(fmt.Errorf("subslice address (%d) is before data address (%d)", hlp.Data, datap.Data))
17	}
18	offset := hlp.Data - datap.Data
19
20	if offset > maxInt {
21		panic(fmt.Errorf("slice offset larger than int (%d)", offset))
22	}
23
24	intoffset := int(offset)
25
26	if intoffset > datap.Len {
27		panic(fmt.Errorf("slice offset (%d) is farther than data length (%d)", intoffset, datap.Len))
28	}
29
30	if intoffset+hlp.Len > datap.Len {
31		panic(fmt.Errorf("slice ends (%d+%d) is farther than data length (%d)", intoffset, hlp.Len, datap.Len))
32	}
33
34	return intoffset
35}
36
37func BytesRange(start []byte, end []byte) []byte {
38	if start == nil || end == nil {
39		panic("cannot call BytesRange with nil")
40	}
41	startp := (*reflect.SliceHeader)(unsafe.Pointer(&start))
42	endp := (*reflect.SliceHeader)(unsafe.Pointer(&end))
43
44	if startp.Data > endp.Data {
45		panic(fmt.Errorf("start pointer address (%d) is after end pointer address (%d)", startp.Data, endp.Data))
46	}
47
48	l := startp.Len
49	endLen := int(endp.Data-startp.Data) + endp.Len
50	if endLen > l {
51		l = endLen
52	}
53
54	if l > startp.Cap {
55		panic(fmt.Errorf("range length is larger than capacity"))
56	}
57
58	return start[:l]
59}
60
61func Stride(ptr unsafe.Pointer, size uintptr, offset int) unsafe.Pointer {
62	// TODO: replace with unsafe.Add when Go 1.17 is released
63	//   https://github.com/golang/go/issues/40481
64	return unsafe.Pointer(uintptr(ptr) + uintptr(int(size)*offset))
65}
66