blob-readwriter.go 1.3 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667
  1. package sqlitex
  2. import (
  3. "errors"
  4. "io"
  5. sqlite "github.com/go-llsqlite/crawshaw"
  6. )
  7. // This wraps a sqlite.Blob with positional state provide extra io implementations.
  8. func NewBlobSeeker(blob *sqlite.Blob) *blobSeeker {
  9. return &blobSeeker{
  10. size: blob.Size(),
  11. blob: blob,
  12. ReaderAt: blob,
  13. WriterAt: blob,
  14. }
  15. }
  16. var _ interface {
  17. io.ReadWriteSeeker
  18. } = (*blobSeeker)(nil)
  19. type blobSeeker struct {
  20. io.ReaderAt
  21. io.WriterAt
  22. blob *sqlite.Blob
  23. off int64
  24. size int64
  25. }
  26. func (blob *blobSeeker) Read(p []byte) (n int, err error) {
  27. if blob.off >= blob.size {
  28. return 0, io.EOF
  29. }
  30. if rem := blob.size - blob.off; int64(len(p)) > rem {
  31. p = p[:rem]
  32. }
  33. n, err = blob.ReadAt(p, blob.off)
  34. blob.off += int64(n)
  35. return n, err
  36. }
  37. func (blob *blobSeeker) Write(p []byte) (n int, err error) {
  38. if rem := blob.size - blob.off; int64(len(p)) > rem {
  39. return 0, io.ErrShortWrite
  40. }
  41. n, err = blob.WriteAt(p, blob.off)
  42. blob.off += int64(n)
  43. return n, err
  44. }
  45. func (blob *blobSeeker) Seek(offset int64, whence int) (int64, error) {
  46. switch whence {
  47. case io.SeekStart:
  48. // use offset directly
  49. case io.SeekCurrent:
  50. offset += blob.off
  51. case io.SeekEnd:
  52. offset += blob.size
  53. }
  54. if offset < 0 {
  55. return blob.off, errors.New("seek to offset < 0")
  56. }
  57. blob.off = offset
  58. return offset, nil
  59. }