266 lines
5.9 KiB
C#
266 lines
5.9 KiB
C#
using Godot;
|
|
using System.Collections.Generic;
|
|
using System.Text;
|
|
|
|
namespace Rokojori
|
|
{
|
|
public partial class BitView
|
|
{
|
|
byte[] _data;
|
|
|
|
int _internalViewOffset = 0;
|
|
public int bitOffset => _internalViewOffset;
|
|
|
|
int _internalViewSize = 0;
|
|
public int numBits => _internalViewSize;
|
|
|
|
public int numBytes => Mathf.CeilToInt( _internalViewSize / 8f );
|
|
|
|
|
|
int _externalPointer = 0;
|
|
public int pointerPosition => _externalPointer;
|
|
|
|
public void SetPointer( int bitPosition )
|
|
{
|
|
_externalPointer = bitPosition;
|
|
}
|
|
|
|
|
|
public byte[] GetBytes()
|
|
{
|
|
var numBytes = this.numBytes;
|
|
var data = new byte[ numBytes ];
|
|
System.Array.Fill( data, (byte)0 );
|
|
|
|
for ( int i = 0; i < _internalViewSize; i++ )
|
|
{
|
|
var isSet = GetValueInternal( i + _internalViewOffset );
|
|
|
|
if ( ! isSet )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
var shift = i % 8;
|
|
var index = i / 8;
|
|
var value = 1 << shift;
|
|
|
|
data[ index ] = (byte) ( data[ index ] | value );
|
|
}
|
|
|
|
|
|
return data;
|
|
}
|
|
|
|
public BitView Clone()
|
|
{
|
|
var clone = new BitView();
|
|
clone._data = _data;
|
|
clone._internalViewOffset = _internalViewOffset;
|
|
clone._internalViewSize = _internalViewSize;
|
|
clone._externalPointer = _externalPointer;
|
|
|
|
return clone;
|
|
}
|
|
|
|
public string GetBitString()
|
|
{
|
|
var output = new StringBuilder();
|
|
|
|
for ( int i = 0; i < _internalViewSize; i++ )
|
|
{
|
|
var mod = i % 8;
|
|
|
|
if ( i != 0 && mod == 0 )
|
|
{
|
|
output.Append( " " );
|
|
}
|
|
|
|
var reverseIndex = 7 - mod * 2;
|
|
|
|
var value = GetValueInternal( reverseIndex + i + _internalViewOffset ) ? "1" : "0";
|
|
output.Append( value );
|
|
}
|
|
|
|
return output.ToString();
|
|
}
|
|
|
|
void SetValueInternal( int position, bool value )
|
|
{
|
|
var byteIndex = position / 8;
|
|
var bitOffset = position - byteIndex * 8;
|
|
|
|
if ( value )
|
|
{
|
|
_data[ byteIndex ] = Bytes.SetBit( _data[ byteIndex ], bitOffset );
|
|
}
|
|
else
|
|
{
|
|
_data[ byteIndex ] = Bytes.UnsetBit( _data[ byteIndex ], bitOffset );
|
|
}
|
|
}
|
|
|
|
bool GetValueInternal( int bitPosition )
|
|
{
|
|
var byteIndex = bitPosition / 8;
|
|
var bitOffset = bitPosition - byteIndex * 8;
|
|
|
|
return Bytes.IsBitSet( _data[ byteIndex ], bitOffset );
|
|
}
|
|
|
|
int GetShiftedValueInternal( int bitPosition, int shift )
|
|
{
|
|
if ( ! GetValueInternal( bitPosition ) )
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
return 1 << shift;
|
|
}
|
|
|
|
void EnsureInternalSize( int bitPosition )
|
|
{
|
|
var byteIndex = bitPosition / 8;
|
|
|
|
if ( byteIndex >= _data.Length )
|
|
{
|
|
var newData = new byte[ _data.Length + 1 ];
|
|
System.Array.Fill( newData, (byte) 0 );
|
|
System.Array.Copy( _data, 0, newData, 0, _data.Length );
|
|
|
|
_data = newData;
|
|
}
|
|
}
|
|
|
|
public void Clear()
|
|
{
|
|
_externalPointer = 0;
|
|
|
|
for ( int i = 0; i < _internalViewSize; i++ )
|
|
{
|
|
SetValueInternal( i + _internalViewOffset, false );
|
|
}
|
|
}
|
|
|
|
public void ResetPointerAndSize()
|
|
{
|
|
_externalPointer = 0;
|
|
_internalViewSize = 0;
|
|
}
|
|
|
|
public void WriteBit( bool value )
|
|
{
|
|
var position = _externalPointer + _internalViewOffset;
|
|
EnsureInternalSize( position );
|
|
|
|
SetValueInternal( position, value );
|
|
_externalPointer ++;
|
|
|
|
_internalViewSize = Mathf.Max( _externalPointer, _internalViewSize );
|
|
}
|
|
|
|
public bool GetBitAt( int bitPosition )
|
|
{
|
|
var internalBitPosition = bitPosition + _internalViewOffset;
|
|
return GetValueInternal( bitPosition );
|
|
}
|
|
|
|
public bool ReadBit()
|
|
{
|
|
var bitPosition = _externalPointer + _internalViewOffset;
|
|
|
|
if ( bitPosition < 0 || bitPosition >= numBits )
|
|
{
|
|
RJLog.Log( "Can't read: >> ", bitPosition, "in", numBits, "p:", _externalPointer, "o:", _internalViewOffset );
|
|
return false;
|
|
}
|
|
var value = GetValueInternal( bitPosition );
|
|
_externalPointer ++;
|
|
|
|
return value;
|
|
}
|
|
|
|
public void SetPointerPosition( int position )
|
|
{
|
|
_externalPointer = Mathf.Clamp( position, 0, _internalViewSize );
|
|
}
|
|
|
|
public static BitView CreateEmpty()
|
|
{
|
|
var view = new BitView();
|
|
view._data = new byte[]{};
|
|
view._internalViewOffset = 0;
|
|
view._internalViewSize = 0;
|
|
view._externalPointer = 0;
|
|
|
|
return view;
|
|
}
|
|
|
|
public static BitView From( byte[] data)
|
|
{
|
|
var view = new BitView();
|
|
|
|
view._data = data;
|
|
view._internalViewOffset = 0;
|
|
view._internalViewSize = data.Length * 8;
|
|
view._externalPointer = 0;
|
|
|
|
return view;
|
|
}
|
|
|
|
|
|
public static BitView From( byte[] data, int bitSize = -1 )
|
|
{
|
|
var view = new BitView();
|
|
|
|
view._data = data;
|
|
view._internalViewOffset = 0;
|
|
view._internalViewSize = bitSize == -1 ? data.Length * 8 : bitSize;
|
|
view._externalPointer = 0;
|
|
|
|
return view;
|
|
}
|
|
|
|
public static BitView PrependBytes( byte[] before, BitView after )
|
|
{
|
|
var data = new byte[ before.Length + after.numBytes ];
|
|
|
|
System.Array.Copy( before, 0, data, 0, before.Length );
|
|
|
|
var view = BitView.From( data, before.Length * 8 + after.numBits );
|
|
|
|
|
|
if ( after.bitOffset == 0 )
|
|
{
|
|
System.Array.Copy( after._data, 0, data, 0, after.numBytes );
|
|
view.SetPointer( after.pointerPosition + before.Length * 8 );
|
|
|
|
return view;
|
|
}
|
|
|
|
view.SetPointer( before.Length * 8 );
|
|
|
|
for ( int i = 0; i < after.numBits; i++ )
|
|
{
|
|
view.WriteBit( after.GetBitAt( i ) );
|
|
}
|
|
|
|
view.SetPointer( after.pointerPosition + before.Length * 8 );
|
|
|
|
return view;
|
|
}
|
|
|
|
public static BitView PrependID( int id, BitView after )
|
|
{
|
|
var idView = BitView.CreateEmpty();
|
|
idView.WriteUIntVL8( id );
|
|
|
|
return BitView.PrependBytes( idView.GetBytes(), after );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
} |