This commit is contained in:
Mike Schwörer 2022-12-20 09:50:13 +01:00
parent 3552acd38b
commit bdb181cb3a
Signed by: Mikescher
GPG Key ID: D3C7172E0A70F8CF

View File

@ -1,56 +1,157 @@
package dataext package dataext
import "io" import (
"errors"
"io"
)
type brcMode int
const (
modeSourceReading = 0
modeSourceFinished = 1
modeBufferReading = 2
modeBufferFinished = 3
)
type BufferedReadCloser interface { type BufferedReadCloser interface {
io.ReadCloser io.ReadCloser
BufferedAll() ([]byte, error) BufferedAll() ([]byte, error)
Reset() error
} }
type bufferedReadCloser struct { type bufferedReadCloser struct {
buffer []byte buffer []byte
inner io.ReadCloser inner io.ReadCloser
finished bool mode brcMode
} off int
func (b *bufferedReadCloser) Read(p []byte) (int, error) {
n, err := b.inner.Read(p)
if n > 0 {
b.buffer = append(b.buffer, p[0:n]...)
}
if err == io.EOF {
b.finished = true
}
return n, err
} }
func NewBufferedReadCloser(sub io.ReadCloser) BufferedReadCloser { func NewBufferedReadCloser(sub io.ReadCloser) BufferedReadCloser {
return &bufferedReadCloser{ return &bufferedReadCloser{
buffer: make([]byte, 0, 1024), buffer: make([]byte, 0, 1024),
inner: sub, inner: sub,
finished: false, mode: modeSourceReading,
off: 0,
}
}
func (b *bufferedReadCloser) Read(p []byte) (int, error) {
switch b.mode {
case modeSourceReading:
n, err := b.inner.Read(p)
if n > 0 {
b.buffer = append(b.buffer, p[0:n]...)
}
if err == io.EOF {
b.mode = modeSourceFinished
}
return n, err
case modeSourceFinished:
return 0, io.EOF
case modeBufferReading:
if len(b.buffer) <= b.off {
b.mode = modeBufferFinished
if len(p) == 0 {
return 0, nil
}
return 0, io.EOF
}
n := copy(p, b.buffer[b.off:])
b.off += n
return n, nil
case modeBufferFinished:
return 0, io.EOF
default:
return 0, errors.New("object in undefined status")
} }
} }
func (b *bufferedReadCloser) Close() error { func (b *bufferedReadCloser) Close() error {
err := b.inner.Close() switch b.mode {
case modeSourceReading:
_, err := b.BufferedAll()
if err != nil { if err != nil {
b.finished = true
}
return err return err
} }
err = b.inner.Close()
if err != nil {
return err
}
b.mode = modeSourceFinished
return nil
case modeSourceFinished:
return nil
case modeBufferReading:
b.mode = modeBufferFinished
return nil
case modeBufferFinished:
return nil
default:
return errors.New("object in undefined status")
}
}
func (b *bufferedReadCloser) BufferedAll() ([]byte, error) { func (b *bufferedReadCloser) BufferedAll() ([]byte, error) {
switch b.mode {
case modeSourceReading:
arr := make([]byte, 1024) arr := make([]byte, 1024)
for !b.finished { for b.mode == modeSourceReading {
_, err := b.Read(arr) _, err := b.Read(arr)
if err != nil && err != io.EOF { if err != nil && err != io.EOF {
return nil, err return nil, err
} }
} }
return b.buffer, nil return b.buffer, nil
case modeSourceFinished:
return b.buffer, nil
case modeBufferReading:
return b.buffer, nil
case modeBufferFinished:
return b.buffer, nil
default:
return nil, errors.New("object in undefined status")
}
}
func (b *bufferedReadCloser) Reset() error {
switch b.mode {
case modeSourceReading:
fallthrough
case modeSourceFinished:
err := b.Close()
if err != nil {
return err
}
b.mode = modeBufferReading
b.off = 0
return nil
case modeBufferReading:
fallthrough
case modeBufferFinished:
b.mode = modeBufferReading
b.off = 0
return nil
default:
return errors.New("object in undefined status")
}
} }