gtsocial-umbx

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

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 }