Skip to content

Commit

Permalink
Add BytesTerminateMulti() and ReadBytesTermMulti()
Browse files Browse the repository at this point in the history
  • Loading branch information
generalmimon committed Aug 2, 2024
1 parent 6569bc9 commit 83c47c9
Show file tree
Hide file tree
Showing 2 changed files with 66 additions and 2 deletions.
44 changes: 42 additions & 2 deletions kaitai/stream.go
Original file line number Diff line number Diff line change
Expand Up @@ -271,8 +271,8 @@ func (k *Stream) ReadBytesPadTerm(size int, term, pad byte, includeTerm bool) ([
}

// ReadBytesTerm reads bytes until the term byte is reached. If includeTerm is
// set the term bytes is included in the returned byte array. If consumeTerm
// is set the stream continues after the term byte. If eosError is set EOF
// true, the term byte is included in the returned byte slice. If consumeTerm is
// true, the stream continues after the term byte. If eosError is true, EOF
// errors result in an error.
func (k *Stream) ReadBytesTerm(term byte, includeTerm, consumeTerm, eosError bool) ([]byte, error) {
r := bufio.NewReader(k)
Expand Down Expand Up @@ -305,6 +305,46 @@ func (k *Stream) ReadBytesTerm(term byte, includeTerm, consumeTerm, eosError boo
return slice, nil
}

// ReadBytesTermMulti reads chunks of len(term) bytes until it reaches a chunk
// equal to term. If includeTerm is true, term will be included in the returned
// byte slice. If consumeTerm is true, stream position will be left after the
// term, otherwise a seek will be performed to get the stream position before
// the term. If eosError is true, reaching EOF before the term is found is
// treated as an error, otherwise no error and all bytes until EOF are returned
// in this case.
func (k *Stream) ReadBytesTermMulti(term []byte, includeTerm, consumeTerm, eosError bool) ([]byte, error) {
unitSize := len(term)
r := []byte{}
c := make([]byte, unitSize)
for {
n, err := io.ReadFull(k, c)
if err != nil {
if errors.Is(err, io.EOF) || errors.Is(err, io.ErrUnexpectedEOF) {
if eosError {
return nil, fmt.Errorf("ReadBytesTermMulti: end of stream reached, but no terminator found")

Check failure on line 324 in kaitai/stream.go

View workflow job for this annotation

GitHub Actions / Lint

do not define dynamic errors, use wrapped static errors instead: "fmt.Errorf(\"ReadBytesTermMulti: end of stream reached, but no terminator found\")" (err113)
}
r = append(r, c[:n]...)
return r, nil
} else {

Check failure on line 328 in kaitai/stream.go

View workflow job for this annotation

GitHub Actions / Lint

indent-error-flow: if block ends with a return statement, so drop this else and outdent its block (revive)
return nil, fmt.Errorf("ReadBytesTermMulti: %w", err)
}
}
if bytes.Equal(c, term) {
if includeTerm {
r = append(r, c...)
}
if !consumeTerm {
_, err := k.Seek(-int64(unitSize), io.SeekCurrent)
if err != nil {
return nil, fmt.Errorf("ReadBytesTermMulti: error seeking back to terminator: %w", err)
}
}
return r, nil
}
r = append(r, c...)
}
}

// AlignToByte discards the remaining bits and starts reading bits at the
// next byte.
func (k *Stream) AlignToByte() {
Expand Down
24 changes: 24 additions & 0 deletions kaitai/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,30 @@ func BytesTerminate(s []byte, term byte, includeTerm bool) []byte {
return s[:newLen]
}

// BytesTerminateMulti terminates the given byte slice using the provided byte
// sequence term, whose first byte must appear at a position that is a multiple
// of len(term). Occurrences at any other positions are ignored. If includeTerm
// is true, term will be included in the returned byte slice.
func BytesTerminateMulti(s, term []byte, includeTerm bool) []byte {
unitSize := len(term)
rest := s
for {
searchIndex := bytes.Index(rest, term)
if searchIndex == -1 {
return s
}
mod := searchIndex % unitSize
if mod == 0 {
newLen := (len(s) - len(rest)) + searchIndex
if includeTerm {
newLen += unitSize
}
return s[:newLen]
}
rest = rest[searchIndex+(unitSize-mod):]
}
}

// BytesStripRight strips bytes of a given value off the end of the byte slice.
func BytesStripRight(s []byte, pad byte) []byte {
n := len(s)
Expand Down

0 comments on commit 83c47c9

Please sign in to comment.