From bdb181cb3a3bfef26d65921322420be4a654a48c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mike=20Schw=C3=B6rer?= Date: Tue, 20 Dec 2022 09:50:13 +0100 Subject: [PATCH] v0.0.37 --- dataext/bufferedReadCloser.go | 165 +++++++++++++++++++++++++++------- 1 file changed, 133 insertions(+), 32 deletions(-) diff --git a/dataext/bufferedReadCloser.go b/dataext/bufferedReadCloser.go index ed3b2fa..59bc825 100644 --- a/dataext/bufferedReadCloser.go +++ b/dataext/bufferedReadCloser.go @@ -1,56 +1,157 @@ package dataext -import "io" +import ( + "errors" + "io" +) + +type brcMode int + +const ( + modeSourceReading = 0 + modeSourceFinished = 1 + modeBufferReading = 2 + modeBufferFinished = 3 +) type BufferedReadCloser interface { io.ReadCloser BufferedAll() ([]byte, error) + Reset() error } type bufferedReadCloser struct { - buffer []byte - inner io.ReadCloser - finished bool -} - -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 + buffer []byte + inner io.ReadCloser + mode brcMode + off int } func NewBufferedReadCloser(sub io.ReadCloser) BufferedReadCloser { return &bufferedReadCloser{ - buffer: make([]byte, 0, 1024), - inner: sub, - finished: false, + buffer: make([]byte, 0, 1024), + inner: sub, + 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 { - err := b.inner.Close() - if err != nil { - b.finished = true + switch b.mode { + case modeSourceReading: + _, err := b.BufferedAll() + if err != nil { + 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") } - return err + } func (b *bufferedReadCloser) BufferedAll() ([]byte, error) { - arr := make([]byte, 1024) - for !b.finished { - _, err := b.Read(arr) - if err != nil && err != io.EOF { - return nil, err + switch b.mode { + case modeSourceReading: + arr := make([]byte, 1024) + for b.mode == modeSourceReading { + _, err := b.Read(arr) + if err != nil && err != io.EOF { + 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") + } }