mirror of
https://github.com/Mezeporta/Erupe.git
synced 2025-12-12 15:04:38 +01:00
376 lines
8.3 KiB
Go
376 lines
8.3 KiB
Go
package byteframe
|
|
|
|
/*
|
|
This is HEAVILY based on the code from
|
|
https://github.com/sinni800/sgemu/blob/master/Core/Packet.go
|
|
*/
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/binary"
|
|
"errors"
|
|
"io"
|
|
"math"
|
|
)
|
|
|
|
// ByteFrame is a struct for reading and writing raw byte data.
|
|
type ByteFrame struct {
|
|
index uint
|
|
usedSize uint
|
|
buf []byte
|
|
byteOrder binary.ByteOrder
|
|
}
|
|
|
|
// NewByteFrame creates a new ByteFrame with valid default values.
|
|
// byteOrder defaults to big endian.
|
|
func NewByteFrame() *ByteFrame {
|
|
b := &ByteFrame{
|
|
index: 0,
|
|
usedSize: 0,
|
|
buf: make([]byte, 4),
|
|
byteOrder: binary.BigEndian,
|
|
}
|
|
return b
|
|
}
|
|
|
|
// NewByteFrameFromBytes creates a new ByteFrame with valid default values.
|
|
// makes a copy of the given buf and initalizes with it.
|
|
// byteOrder defaults to big endian.
|
|
func NewByteFrameFromBytes(buf []byte) *ByteFrame {
|
|
b := &ByteFrame{
|
|
index: 0,
|
|
usedSize: uint(len(buf)),
|
|
buf: make([]byte, len(buf)),
|
|
byteOrder: binary.BigEndian,
|
|
}
|
|
copy(b.buf, buf)
|
|
return b
|
|
}
|
|
|
|
// grow either doubles the backing buffer size, or grows it by the size specified, whichever is larger.
|
|
func (b *ByteFrame) grow(size uint) {
|
|
bytesToAdd := uint(0)
|
|
if size > uint(len(b.buf)) {
|
|
bytesToAdd = size
|
|
} else {
|
|
bytesToAdd = uint(len(b.buf))
|
|
}
|
|
|
|
newBuf := make([]byte, uint(len(b.buf))+bytesToAdd)
|
|
copy(newBuf, b.buf)
|
|
b.buf = newBuf
|
|
}
|
|
|
|
// wcheck checks if we have enough space to write.
|
|
func (b *ByteFrame) wcheck(size uint) {
|
|
if b.index+size > uint(len(b.buf)) {
|
|
b.grow(size)
|
|
}
|
|
}
|
|
|
|
// wprologue is a helpler function to update state after a write.
|
|
func (b *ByteFrame) wprologue(size uint) {
|
|
|
|
tmp := int(b.index+size) - int(b.usedSize)
|
|
if tmp > 0 {
|
|
b.usedSize += uint(tmp)
|
|
}
|
|
|
|
b.index += size
|
|
}
|
|
|
|
// rcheck checks if we have enough data to read.
|
|
func (b *ByteFrame) rcheck(size uint) bool {
|
|
if b.index+size > uint(len(b.buf)) || b.index+size > b.usedSize+1 {
|
|
return false
|
|
}
|
|
return true
|
|
}
|
|
|
|
func (b *ByteFrame) rprologue(size uint) {
|
|
b.index += size
|
|
}
|
|
|
|
func (b *ByteFrame) rerr() {
|
|
panic("Error while reading!")
|
|
}
|
|
|
|
// Seek (implements the io.Seeker interface)
|
|
func (b *ByteFrame) Seek(offset int64, whence int) (int64, error) {
|
|
switch whence {
|
|
case io.SeekStart:
|
|
if offset > int64(b.usedSize) {
|
|
return int64(b.index), errors.New("cannot seek beyond the max index")
|
|
}
|
|
b.index = uint(offset)
|
|
break
|
|
case io.SeekCurrent:
|
|
newPos := int64(b.index) + offset
|
|
if newPos > int64(b.usedSize) {
|
|
return int64(b.index), errors.New("cannot seek beyond the max index")
|
|
} else if newPos < 0 {
|
|
return int64(b.index), errors.New("cannot seek before the buffer start")
|
|
}
|
|
b.index = uint(newPos)
|
|
break
|
|
case io.SeekEnd:
|
|
newPos := int64(b.usedSize) + offset
|
|
if newPos > int64(b.usedSize) {
|
|
return int64(b.index), errors.New("cannot seek beyond the max index")
|
|
} else if newPos < 0 {
|
|
return int64(b.index), errors.New("cannot seek before the buffer start")
|
|
}
|
|
b.index = uint(newPos)
|
|
break
|
|
|
|
}
|
|
|
|
return int64(b.index), nil
|
|
}
|
|
|
|
// Data returns the data from the buffer start up to the max index.
|
|
func (b *ByteFrame) Data() []byte {
|
|
return b.buf[:b.usedSize]
|
|
}
|
|
|
|
// DataFromCurrent returns the data from the current index up to the max index.
|
|
func (b *ByteFrame) DataFromCurrent() []byte {
|
|
return b.buf[b.index:b.usedSize]
|
|
}
|
|
|
|
// SetLE sets the byte order to litte endian.
|
|
func (b *ByteFrame) SetLE() {
|
|
b.byteOrder = binary.LittleEndian
|
|
}
|
|
|
|
// SetBE sets the byte order to big endian.
|
|
func (b *ByteFrame) SetBE() {
|
|
b.byteOrder = binary.BigEndian
|
|
}
|
|
|
|
// WriteUint8 writes a uint8 at the current index.
|
|
func (b *ByteFrame) WriteUint8(x uint8) {
|
|
b.wcheck(1)
|
|
b.buf[b.index] = x
|
|
b.wprologue(1)
|
|
}
|
|
|
|
// WriteBool writes a bool at the current index
|
|
// (1 byte. true -> 1, false -> 0)
|
|
func (b *ByteFrame) WriteBool(x bool) {
|
|
if x {
|
|
b.WriteUint8(1)
|
|
} else {
|
|
b.WriteUint8(0)
|
|
}
|
|
}
|
|
|
|
// WriteUint16 writes a uint16 at the current index.
|
|
func (b *ByteFrame) WriteUint16(x uint16) {
|
|
b.wcheck(2)
|
|
b.byteOrder.PutUint16(b.buf[b.index:], x)
|
|
b.wprologue(2)
|
|
}
|
|
|
|
// WriteUint32 writes a uint32 at the current index.
|
|
func (b *ByteFrame) WriteUint32(x uint32) {
|
|
b.wcheck(4)
|
|
b.byteOrder.PutUint32(b.buf[b.index:], x)
|
|
b.wprologue(4)
|
|
}
|
|
|
|
// WriteUint64 writes a uint64 at the current index.
|
|
func (b *ByteFrame) WriteUint64(x uint64) {
|
|
b.wcheck(8)
|
|
b.byteOrder.PutUint64(b.buf[b.index:], x)
|
|
b.wprologue(8)
|
|
}
|
|
|
|
// WriteInt8 writes a int8 at the current index.
|
|
func (b *ByteFrame) WriteInt8(x int8) {
|
|
b.wcheck(1)
|
|
b.buf[b.index] = byte(x)
|
|
b.wprologue(1)
|
|
}
|
|
|
|
// WriteInt16 writes a int16 at the current index.
|
|
func (b *ByteFrame) WriteInt16(x int16) {
|
|
b.wcheck(2)
|
|
b.byteOrder.PutUint16(b.buf[b.index:], uint16(x))
|
|
b.wprologue(2)
|
|
}
|
|
|
|
// WriteInt32 writes a int32 at the current index.
|
|
func (b *ByteFrame) WriteInt32(x int32) {
|
|
b.wcheck(4)
|
|
b.byteOrder.PutUint32(b.buf[b.index:], uint32(x))
|
|
b.wprologue(4)
|
|
}
|
|
|
|
// WriteInt64 writes a int64 at the current index.
|
|
func (b *ByteFrame) WriteInt64(x int64) {
|
|
b.wcheck(8)
|
|
b.byteOrder.PutUint64(b.buf[b.index:], uint64(x))
|
|
b.wprologue(8)
|
|
}
|
|
|
|
// WriteFloat32 writes a float32 at the current index.
|
|
func (b *ByteFrame) WriteFloat32(x float32) {
|
|
b.wcheck(4)
|
|
tmp := math.Float32bits(x)
|
|
b.byteOrder.PutUint32(b.buf[b.index:], tmp)
|
|
b.wprologue(4)
|
|
}
|
|
|
|
// WriteFloat64 writes a float64 at the current index
|
|
func (b *ByteFrame) WriteFloat64(x float64) {
|
|
b.wcheck(8)
|
|
tmp := math.Float64bits(x)
|
|
b.byteOrder.PutUint64(b.buf[b.index:], tmp)
|
|
b.wprologue(8)
|
|
}
|
|
|
|
// WriteBytes writes a slice of bytes at the current index.
|
|
func (b *ByteFrame) WriteBytes(x []byte) {
|
|
b.wcheck(uint(len(x)))
|
|
copy(b.buf[b.index:], x)
|
|
b.wprologue(uint(len(x)))
|
|
}
|
|
|
|
// WriteNullTerminatedBytes write a slice bytes with an additional NULL terminator.
|
|
func (b *ByteFrame) WriteNullTerminatedBytes(x []byte) {
|
|
b.WriteBytes(x)
|
|
b.WriteUint8(0)
|
|
}
|
|
|
|
// ReadUint8 reads a uint8 at the current index.
|
|
func (b *ByteFrame) ReadUint8() (x uint8) {
|
|
if !b.rcheck(1) {
|
|
b.rerr()
|
|
}
|
|
x = uint8(b.buf[b.index])
|
|
b.rprologue(1)
|
|
return
|
|
}
|
|
|
|
// ReadBool reads a bool at the current index
|
|
// (1 byte. b > 0 -> true, b == 0 -> false)
|
|
func (b *ByteFrame) ReadBool() (x bool) {
|
|
tmp := b.ReadUint8()
|
|
x = tmp > 0
|
|
return
|
|
}
|
|
|
|
// ReadUint16 reads a uint16 at the current index.
|
|
func (b *ByteFrame) ReadUint16() (x uint16) {
|
|
if !b.rcheck(2) {
|
|
b.rerr()
|
|
}
|
|
x = b.byteOrder.Uint16(b.buf[b.index:])
|
|
b.rprologue(2)
|
|
return
|
|
}
|
|
|
|
// ReadUint32 reads a uint32 at the current index.
|
|
func (b *ByteFrame) ReadUint32() (x uint32) {
|
|
if !b.rcheck(4) {
|
|
b.rerr()
|
|
}
|
|
x = b.byteOrder.Uint32(b.buf[b.index:])
|
|
b.rprologue(4)
|
|
return
|
|
}
|
|
|
|
// ReadUint64 reads a uint64 at the current index.
|
|
func (b *ByteFrame) ReadUint64() (x uint64) {
|
|
if !b.rcheck(8) {
|
|
b.rerr()
|
|
}
|
|
x = b.byteOrder.Uint64(b.buf[b.index:])
|
|
b.rprologue(8)
|
|
return
|
|
}
|
|
|
|
// ReadInt8 reads a int8 at the current index.
|
|
func (b *ByteFrame) ReadInt8() (x int8) {
|
|
if !b.rcheck(1) {
|
|
b.rerr()
|
|
}
|
|
x = int8(b.buf[b.index])
|
|
b.rprologue(1)
|
|
return
|
|
}
|
|
|
|
// ReadInt16 reads a int16 at the current index.
|
|
func (b *ByteFrame) ReadInt16() (x int16) {
|
|
if !b.rcheck(2) {
|
|
b.rerr()
|
|
}
|
|
x = int16(b.byteOrder.Uint16(b.buf[b.index:]))
|
|
b.rprologue(2)
|
|
return
|
|
}
|
|
|
|
// ReadInt32 reads a int32 at the current index.
|
|
func (b *ByteFrame) ReadInt32() (x int32) {
|
|
if !b.rcheck(4) {
|
|
b.rerr()
|
|
}
|
|
x = int32(b.byteOrder.Uint32(b.buf[b.index:]))
|
|
b.rprologue(4)
|
|
return
|
|
}
|
|
|
|
// ReadInt64 reads a int64 at the current index.
|
|
func (b *ByteFrame) ReadInt64() (x int64) {
|
|
if !b.rcheck(8) {
|
|
b.rerr()
|
|
}
|
|
x = int64(b.byteOrder.Uint64(b.buf[b.index:]))
|
|
b.rprologue(8)
|
|
return
|
|
}
|
|
|
|
// ReadFloat32 reads a float32 at the current index.
|
|
func (b *ByteFrame) ReadFloat32() (x float32) {
|
|
if !b.rcheck(4) {
|
|
b.rerr()
|
|
}
|
|
x = math.Float32frombits(b.byteOrder.Uint32(b.buf[b.index:]))
|
|
b.rprologue(4)
|
|
return
|
|
}
|
|
|
|
// ReadFloat64 reads a float64 at the current index.
|
|
func (b *ByteFrame) ReadFloat64() (x float64) {
|
|
if !b.rcheck(8) {
|
|
b.rerr()
|
|
}
|
|
x = math.Float64frombits(b.byteOrder.Uint64(b.buf[b.index:]))
|
|
b.rprologue(8)
|
|
return
|
|
}
|
|
|
|
// ReadBytes reads `size` many bytes at the current index.
|
|
func (b *ByteFrame) ReadBytes(size uint) (x []byte) {
|
|
if !b.rcheck(size) {
|
|
b.rerr()
|
|
}
|
|
x = b.buf[b.index : b.index+size]
|
|
b.rprologue(size)
|
|
return
|
|
}
|
|
|
|
// ReadNullTerminatedBytes reads bytes up to a NULL terminator.
|
|
func (b *ByteFrame) ReadNullTerminatedBytes() []byte {
|
|
tmpData := b.DataFromCurrent()
|
|
tmp := bytes.SplitN(tmpData, []byte{0x00}, 2)[0]
|
|
|
|
if len(tmp) == len(tmpData) {
|
|
return []byte{}
|
|
}
|
|
|
|
b.rprologue(uint(len(tmp)) + 1)
|
|
return tmp
|
|
}
|