GoSBHPF/pkg/seekablebuffer/seekablebuffer.go
zervo 96f0b64a11 Add SeekableBuffer
Add a specialised bytes.Buffer variant with seeking capabilities. This allows writers without seeking support to serialize using NodeSerializerStreamed.
2025-02-14 12:04:04 +01:00

90 lines
1.6 KiB
Go

/*
SeekableBuffer
Copyright (c) 2023 aler9
Copyright (c) 2025 Zervó Zadachin
Implementation based on code from "bluenviron/mediacommon".
See: https://github.com/bluenviron/mediacommon/blob/main/pkg/formats/fmp4/seekablebuffer/seekablebuffer.go
Original code was licensed under the MIT License.
See: https://github.com/bluenviron/mediacommon/blob/main/LICENSE
*/
package seekablebuffer
import (
"bytes"
"fmt"
"io"
)
// Buffer is a bytes.Buffer with an additional Seek() method.
type Buffer struct {
bytes.Buffer
pos int64
}
// Write implements io.Writer.
func (b *Buffer) Write(p []byte) (int, error) {
var n int
if b.pos < int64(b.Len()) {
n = copy(b.Bytes()[b.pos:], p)
p = p[n:]
}
if len(p) > 0 {
// Buffer.Write should never return an error here.
nn, _ := b.Buffer.Write(p)
n += nn
}
b.pos += int64(n)
return n, nil
}
// Read (almost) implements io.Reader.
func (b *Buffer) Read(_ []byte) (int, error) {
return 0, fmt.Errorf("read not implemented")
}
// Seek implements io.Seeker.
func (b *Buffer) Seek(offset int64, whence int) (int64, error) {
var pos2 int64
switch whence {
case io.SeekStart:
pos2 = offset
case io.SeekCurrent:
pos2 = b.pos + offset
case io.SeekEnd:
pos2 = int64(b.Len()) + offset
default:
return 0, fmt.Errorf("invalid seek whence")
}
if pos2 < 0 {
return 0, fmt.Errorf("negative position")
}
b.pos = pos2
// Expand buffer if needed
diff := b.pos - int64(b.Len())
if diff > 0 {
// Buffer.Write should never return an error here.
b.Buffer.Write(make([]byte, diff))
}
return pos2, nil
}
// Reset resets the buffer state.
func (b *Buffer) Reset() {
b.Buffer.Reset()
b.pos = 0
}