117 lines
2.2 KiB
Go
117 lines
2.2 KiB
Go
package exiftool
|
|
|
|
import (
|
|
"bytes"
|
|
"errors"
|
|
"io"
|
|
)
|
|
|
|
// MarkReader reads from upstream and stops at marker boundaries.
|
|
type MarkReader struct {
|
|
upstream io.Reader
|
|
buf []byte
|
|
mark []byte
|
|
|
|
// valid data: buf[start:pending]
|
|
// pending, need to check if contains mark: buf[pending:end]
|
|
start int
|
|
pending int
|
|
end int
|
|
|
|
// if true, mark begins from buf[pending]
|
|
hasMark bool
|
|
// if true, upstream is EOF
|
|
upstreamEOF bool
|
|
// if true, this reader returns EOF
|
|
paused bool
|
|
}
|
|
|
|
// NewMarkReader creates a reader that stops at each marker and requires Reset to continue.
|
|
func NewMarkReader(upstream io.Reader, bufferSize int, mark string) (*MarkReader, error) {
|
|
if bufferSize < 2*len(mark) {
|
|
return nil, errors.New("buffer too small")
|
|
}
|
|
|
|
return &MarkReader{
|
|
upstream: upstream,
|
|
buf: make([]byte, bufferSize),
|
|
mark: []byte(mark),
|
|
}, nil
|
|
}
|
|
|
|
// Reset resumes reading after a previously encountered marker boundary.
|
|
func (r *MarkReader) Reset() {
|
|
r.paused = false
|
|
}
|
|
|
|
// Read returns bytes up to (but excluding) the next marker, then reports EOF until Reset.
|
|
func (r *MarkReader) Read(p []byte) (int, error) {
|
|
if len(p) == 0 {
|
|
return 0, nil
|
|
}
|
|
|
|
if r.paused {
|
|
return 0, io.EOF
|
|
}
|
|
|
|
if r.start == r.pending {
|
|
// compact buffer
|
|
copy(r.buf[0:], r.buf[r.start:r.end])
|
|
r.end -= r.start
|
|
r.pending -= r.start
|
|
r.start = 0
|
|
|
|
// fill buffer
|
|
n, err := io.ReadAtLeast(r.upstream, r.buf[r.end:], len(r.mark))
|
|
r.end += n
|
|
if err == io.EOF || err == io.ErrUnexpectedEOF {
|
|
r.upstreamEOF = true
|
|
err = nil
|
|
}
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
|
|
r.checkMarkInPending()
|
|
}
|
|
|
|
// read from valid data
|
|
n := copy(p, r.buf[r.start:r.pending])
|
|
r.start += n
|
|
|
|
if r.start == r.pending {
|
|
switch {
|
|
case r.hasMark:
|
|
r.pending += len(r.mark)
|
|
r.start += len(r.mark)
|
|
r.hasMark = false
|
|
r.paused = true
|
|
|
|
r.checkMarkInPending()
|
|
case r.upstreamEOF:
|
|
r.paused = r.start == r.end
|
|
}
|
|
}
|
|
|
|
if r.paused {
|
|
return n, io.EOF
|
|
}
|
|
|
|
return n, nil
|
|
}
|
|
|
|
func (r *MarkReader) checkMarkInPending() {
|
|
if markAt := bytes.Index(r.buf[r.pending:r.end], r.mark); markAt >= 0 {
|
|
r.hasMark = true
|
|
r.pending = r.pending + markAt
|
|
return
|
|
}
|
|
|
|
if r.upstreamEOF {
|
|
r.pending = r.end
|
|
return
|
|
}
|
|
|
|
r.pending = max(r.pending, r.end-len(r.mark)+1)
|
|
}
|