seekable_buffer.go (3187B)
1 package rifs 2 3 import ( 4 "io" 5 "os" 6 7 "github.com/dsoprea/go-logging" 8 ) 9 10 // SeekableBuffer is a simple memory structure that satisfies 11 // `io.ReadWriteSeeker`. 12 type SeekableBuffer struct { 13 data []byte 14 position int64 15 } 16 17 // NewSeekableBuffer is a factory that returns a `*SeekableBuffer`. 18 func NewSeekableBuffer() *SeekableBuffer { 19 data := make([]byte, 0) 20 21 return &SeekableBuffer{ 22 data: data, 23 } 24 } 25 26 // NewSeekableBufferWithBytes is a factory that returns a `*SeekableBuffer`. 27 func NewSeekableBufferWithBytes(originalData []byte) *SeekableBuffer { 28 data := make([]byte, len(originalData)) 29 copy(data, originalData) 30 31 return &SeekableBuffer{ 32 data: data, 33 } 34 } 35 36 func len64(data []byte) int64 { 37 return int64(len(data)) 38 } 39 40 // Bytes returns the underlying slice. 41 func (sb *SeekableBuffer) Bytes() []byte { 42 return sb.data 43 } 44 45 // Len returns the number of bytes currently stored. 46 func (sb *SeekableBuffer) Len() int { 47 return len(sb.data) 48 } 49 50 // Write does a standard write to the internal slice. 51 func (sb *SeekableBuffer) Write(p []byte) (n int, err error) { 52 defer func() { 53 if state := recover(); state != nil { 54 err = log.Wrap(state.(error)) 55 } 56 }() 57 58 // The current position we're already at is past the end of the data we 59 // actually have. Extend our buffer up to our current position. 60 if sb.position > len64(sb.data) { 61 extra := make([]byte, sb.position-len64(sb.data)) 62 sb.data = append(sb.data, extra...) 63 } 64 65 positionFromEnd := len64(sb.data) - sb.position 66 tailCount := positionFromEnd - len64(p) 67 68 var tailBytes []byte 69 if tailCount > 0 { 70 tailBytes = sb.data[len64(sb.data)-tailCount:] 71 sb.data = append(sb.data[:sb.position], p...) 72 } else { 73 sb.data = append(sb.data[:sb.position], p...) 74 } 75 76 if tailBytes != nil { 77 sb.data = append(sb.data, tailBytes...) 78 } 79 80 dataSize := len64(p) 81 sb.position += dataSize 82 83 return int(dataSize), nil 84 } 85 86 // Read does a standard read against the internal slice. 87 func (sb *SeekableBuffer) Read(p []byte) (n int, err error) { 88 defer func() { 89 if state := recover(); state != nil { 90 err = log.Wrap(state.(error)) 91 } 92 }() 93 94 if sb.position >= len64(sb.data) { 95 return 0, io.EOF 96 } 97 98 n = copy(p, sb.data[sb.position:]) 99 sb.position += int64(n) 100 101 return n, nil 102 } 103 104 // Truncate either chops or extends the internal buffer. 105 func (sb *SeekableBuffer) Truncate(size int64) (err error) { 106 defer func() { 107 if state := recover(); state != nil { 108 err = log.Wrap(state.(error)) 109 } 110 }() 111 112 sizeInt := int(size) 113 if sizeInt < len(sb.data)-1 { 114 sb.data = sb.data[:sizeInt] 115 } else { 116 new := make([]byte, sizeInt-len(sb.data)) 117 sb.data = append(sb.data, new...) 118 } 119 120 return nil 121 } 122 123 // Seek does a standard seek on the internal slice. 124 func (sb *SeekableBuffer) Seek(offset int64, whence int) (n int64, err error) { 125 defer func() { 126 if state := recover(); state != nil { 127 err = log.Wrap(state.(error)) 128 } 129 }() 130 131 if whence == os.SEEK_SET { 132 sb.position = offset 133 } else if whence == os.SEEK_END { 134 sb.position = len64(sb.data) + offset 135 } else if whence == os.SEEK_CUR { 136 sb.position += offset 137 } else { 138 log.Panicf("seek whence is not valid: (%d)", whence) 139 } 140 141 if sb.position < 0 { 142 sb.position = 0 143 } 144 145 return sb.position, nil 146 }