lychee-slicer/asar/storage.go
2024-10-20 23:04:38 +02:00

99 lines
1.9 KiB
Go

package asar
import (
"bytes"
"errors"
"io"
)
type SizedReaderAt interface {
io.ReaderAt
Size() int64
}
type WriterReaderAtWriterTo interface {
io.Writer
io.ReaderAt
io.WriterTo
}
type BytesReadAtWriter struct {
s []byte
i int64
}
func NewBytesReadAtWriter(s []byte) *BytesReadAtWriter {
return &BytesReadAtWriter{s: s, i: 0}
}
func (b *BytesReadAtWriter) Write(p []byte) (n int, err error) {
b.s = append(b.s, p...)
return len(p), nil
}
func (b *BytesReadAtWriter) ReadAt(p []byte, off int64) (n int, err error) {
// cannot modify state - see io.ReaderAt
if off < 0 {
return 0, errors.New("negative offset")
}
if off >= int64(len(b.s)) {
return 0, io.EOF
}
n = copy(p, b.s[off:])
if n < len(p) {
err = io.EOF
}
return
}
func (b *BytesReadAtWriter) WriteTo(w io.Writer) (n int64, err error) {
return io.Copy(w, bytes.NewReader(b.s))
}
type FilesystemStorage struct {
existing SizedReaderAt
new WriterReaderAtWriterTo
newOffset int64
}
func NewFilesystemStorage(existing SizedReaderAt, new WriterReaderAtWriterTo) *FilesystemStorage {
return &FilesystemStorage{
existing: existing,
new: new,
newOffset: 0,
}
}
func (fs *FilesystemStorage) Size() int64 {
return fs.existing.Size() + fs.newOffset
}
func (fs *FilesystemStorage) ReadAt(p []byte, off int64) (n int, err error) {
existingSize := fs.existing.Size()
if off < existingSize {
// error when cross boundary
if off+int64(len(p)) > existingSize {
return 0, io.ErrUnexpectedEOF
}
return fs.existing.ReadAt(p, off)
}
return fs.new.ReadAt(p, off-existingSize)
}
func (fs *FilesystemStorage) Write(p []byte) (n int, err error) {
n, err = fs.new.Write(p)
fs.newOffset += int64(n)
return
}
func (fs *FilesystemStorage) WriteTo(w io.Writer) (n int64, err error) {
// write existing
n, err = io.Copy(w, io.NewSectionReader(fs.existing, 0, fs.existing.Size()))
if err != nil {
return n, err
}
n2, err := fs.new.WriteTo(w)
return n + n2, err
}