gtsocial-umbx

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

strings.go (3055B)


      1 package btf
      2 
      3 import (
      4 	"bufio"
      5 	"bytes"
      6 	"errors"
      7 	"fmt"
      8 	"io"
      9 )
     10 
     11 type stringTable struct {
     12 	base    *stringTable
     13 	offsets []uint32
     14 	strings []string
     15 }
     16 
     17 // sizedReader is implemented by bytes.Reader, io.SectionReader, strings.Reader, etc.
     18 type sizedReader interface {
     19 	io.Reader
     20 	Size() int64
     21 }
     22 
     23 func readStringTable(r sizedReader, base *stringTable) (*stringTable, error) {
     24 	// When parsing split BTF's string table, the first entry offset is derived
     25 	// from the last entry offset of the base BTF.
     26 	firstStringOffset := uint32(0)
     27 	if base != nil {
     28 		idx := len(base.offsets) - 1
     29 		firstStringOffset = base.offsets[idx] + uint32(len(base.strings[idx])) + 1
     30 	}
     31 
     32 	// Derived from vmlinux BTF.
     33 	const averageStringLength = 16
     34 
     35 	n := int(r.Size() / averageStringLength)
     36 	offsets := make([]uint32, 0, n)
     37 	strings := make([]string, 0, n)
     38 
     39 	offset := firstStringOffset
     40 	scanner := bufio.NewScanner(r)
     41 	scanner.Split(splitNull)
     42 	for scanner.Scan() {
     43 		str := scanner.Text()
     44 		offsets = append(offsets, offset)
     45 		strings = append(strings, str)
     46 		offset += uint32(len(str)) + 1
     47 	}
     48 	if err := scanner.Err(); err != nil {
     49 		return nil, err
     50 	}
     51 
     52 	if len(strings) == 0 {
     53 		return nil, errors.New("string table is empty")
     54 	}
     55 
     56 	if firstStringOffset == 0 && strings[0] != "" {
     57 		return nil, errors.New("first item in string table is non-empty")
     58 	}
     59 
     60 	return &stringTable{base, offsets, strings}, nil
     61 }
     62 
     63 func splitNull(data []byte, atEOF bool) (advance int, token []byte, err error) {
     64 	i := bytes.IndexByte(data, 0)
     65 	if i == -1 {
     66 		if atEOF && len(data) > 0 {
     67 			return 0, nil, errors.New("string table isn't null terminated")
     68 		}
     69 		return 0, nil, nil
     70 	}
     71 
     72 	return i + 1, data[:i], nil
     73 }
     74 
     75 func (st *stringTable) Lookup(offset uint32) (string, error) {
     76 	if st.base != nil && offset <= st.base.offsets[len(st.base.offsets)-1] {
     77 		return st.base.lookup(offset)
     78 	}
     79 	return st.lookup(offset)
     80 }
     81 
     82 func (st *stringTable) lookup(offset uint32) (string, error) {
     83 	i := search(st.offsets, offset)
     84 	if i == len(st.offsets) || st.offsets[i] != offset {
     85 		return "", fmt.Errorf("offset %d isn't start of a string", offset)
     86 	}
     87 
     88 	return st.strings[i], nil
     89 }
     90 
     91 func (st *stringTable) Length() int {
     92 	last := len(st.offsets) - 1
     93 	return int(st.offsets[last]) + len(st.strings[last]) + 1
     94 }
     95 
     96 func (st *stringTable) Marshal(w io.Writer) error {
     97 	for _, str := range st.strings {
     98 		_, err := io.WriteString(w, str)
     99 		if err != nil {
    100 			return err
    101 		}
    102 		_, err = w.Write([]byte{0})
    103 		if err != nil {
    104 			return err
    105 		}
    106 	}
    107 	return nil
    108 }
    109 
    110 // search is a copy of sort.Search specialised for uint32.
    111 //
    112 // Licensed under https://go.dev/LICENSE
    113 func search(ints []uint32, needle uint32) int {
    114 	// Define f(-1) == false and f(n) == true.
    115 	// Invariant: f(i-1) == false, f(j) == true.
    116 	i, j := 0, len(ints)
    117 	for i < j {
    118 		h := int(uint(i+j) >> 1) // avoid overflow when computing h
    119 		// i ≤ h < j
    120 		if !(ints[h] >= needle) {
    121 			i = h + 1 // preserves f(i-1) == false
    122 		} else {
    123 			j = h // preserves f(j) == true
    124 		}
    125 	}
    126 	// i == j, f(i-1) == false, and f(j) (= f(i)) == true  =>  answer is i.
    127 	return i
    128 }