SRO.IO.DataBag 1.0.1

SRO.IO.DataBag

SRO.IO.DataBag is a .NET library that provides flexible, auto-expanding in-memory data containers for binary and text manipulation. The three core classes — ByteBag, PrimitiveBag, and TextManager — act as managed buffers with a consistent position/limit/mark navigation model, direct file I/O, and full compatibility with the standard .NET Stream, TextReader, and TextWriter abstractions.

Target Frameworks

Framework Version
.NET 8.0
.NET Framework 4.8
.NET Framework 4.7.2

Namespace

using SRO.IO.DataBag;

Class Overview

Class Base Unit Purpose
ByteBag System.IO.Stream byte Auto-expanding byte buffer; direct Stream integration
PrimitiveBag ByteBag byte Adds typed read/write for primitives and UTF-8 strings; configurable endianness
TextManager — char Auto-expanding character buffer with a full StringBuilder-equivalent API and TextReader/TextWriter access
TextManagerReader TextReader char TextReader adapter backed by a TextManager (obtained via TextManager.Reader)
TextManagerWriter TextWriter char TextWriter adapter backed by a TextManager (obtained via TextManager.Writer)
ByteBagException Exception — Base exception for all DataBag errors
BagUnderflowException ByteBagException — Thrown when a Get call requests more data than is available
BagDataFormatException ByteBagException — Thrown when data is malformed (e.g., an invalid UTF-8 sequence)

The Position / Limit / Mark Model

All three containers share the same buffer navigation pattern. Understanding this model is the key to using the API correctly.

Concept Description
Position The current read or write cursor. Advances automatically as data is put or retrieved.
Limit The logical end of the data currently in the container.
Mark A saved position that can be restored with Reset().

Write → Read lifecycle

Put(data)  →  Flip()  →  Get(data)
  • After writing with Put(), the position is at the end of the written data and the limit equals that position.
  • Calling Flip() sets the limit to the current position and resets the position to zero, making the container ready for sequential reading.
  • Rewind() resets only the position to zero without changing the limit, allowing data to be re-read.
  • Last() moves the position back to the limit, allowing more data to be appended after a read.
var bag = new ByteBag();
bag.Put(new byte[] { 10, 20, 30 });

bag.Flip();                    // ready to read
byte a = bag.Get();            // 10
byte b = bag.Get();            // 20

bag.Rewind();                  // back to position 0
byte first = bag.Get();        // 10 again

bag.Last();                    // position at end — ready to append
bag.Put(40);

ByteBag

ByteBag implements System.IO.Stream, so it can be used anywhere a Stream is accepted. Its backing array grows automatically (similar to StringBuilder), eliminating the need to pre-size buffers.

Constructors

var bag1 = new ByteBag();                     // default capacity (1000 bytes)
var bag2 = new ByteBag(4096);                 // specified initial capacity
var bag3 = new ByteBag(existingByteArray);    // wrap an existing array (requires Flip() before reading)
var bag4 = new ByteBag("Hello, world");       // initialize from a string

Writing data

var bag = new ByteBag();

bag.Put((byte)0xFF);                          // single byte
bag.Put(buffer, offset, length);              // byte array slice
bag.Append("header: ");                       // string as bytes
bag.AppendLine("value = 42");                 // string + newline
bag.AppendFormat("count={0}", 7);             // formatted string

bag.Insert(0, new byte[] { 0x01, 0x02 });    // insert at position
bag.Replace(4, src, 0, src.Length);          // overwrite a section
bag.Delete(10, 20);                          // remove a range

Reading data

bag.Flip();                                   // switch to read mode

byte single    = bag.Get();                   // one byte
bag.Get(buffer, 0, buffer.Length);           // fill a buffer
long available = bag.Available;              // how many bytes remain

File I/O

// Load
var bag = new ByteBag();
bag.Load(new FileInfo(@"C:\data\payload.bin"));

// Save to same path
bag.Name = @"C:\data\output.bin";
bag.Save();

// Save to a new path
bag.Save(new FileInfo(@"C:\data\copy.bin"));

// Stream-to-stream transfer
bag.LoadFromStream(someInputStream);
bag.SaveToStream(someOutputStream);

Stream and TextReader / TextWriter access

Because ByteBag extends Stream, it can be wrapped directly:

var bag = new ByteBag();

using (var writer = new StreamWriter(bag))
{
    writer.WriteLine("Hello from StreamWriter");
}

bag.Flip();

using (var reader = new StreamReader(bag))
{
    string line = reader.ReadLine();
}

The convenience properties Reader and Writer provide cached StreamReader / StreamWriter instances that do not need to be closed:

var bag = new ByteBag();
bag.Writer.WriteLine("cached writer");

bag.Flip();
string text = bag.Reader.ReadToEnd();

Useful properties

Property Type Description
Length long Number of bytes currently stored
Position long Current read/write cursor
Available long Bytes remaining to read (Limit - Position)
Capacity int Size of the backing array
Bytes byte[] Snapshot copy of the stored data
Name string Optional label or file path (used by parameterless Save())
Encoding Encoding Encoding used for string/byte conversions (default: Encoding.Default)
MovementBufferSize int Buffer size used for stream-to-stream transfers (default: 8192)
this[int index] byte Direct indexed access to individual bytes

PrimitiveBag

PrimitiveBag extends ByteBag with typed read and write methods for common .NET primitive types. It supports both big-endian (default) and little-endian byte ordering and includes UTF-8 string handling that is compatible with the JVM class file format (a 2-byte length prefix followed by modified UTF-8 bytes).

Constructors

var pb = new PrimitiveBag();
var pb = new PrimitiveBag(4096);
var pb = new PrimitiveBag(existingByteArray);

Endianness

var pb = new PrimitiveBag();
pb.BigEndian = true;   // default — network byte order
pb.BigEndian = false;  // little-endian (Intel byte order)

Writing primitives

var pb = new PrimitiveBag();

pb.PutChar('A');
pb.PutShort(1024);
pb.PutInt(100_000);
pb.PutLong(9_000_000_000L);
pb.PutFloat(3.14f);
pb.PutDouble(2.718281828);
pb.PutUnsignedShort(65535);
pb.PutUTF("Hello, world");   // 2-byte length prefix + modified UTF-8 bytes

Reading primitives

pb.Flip();   // switch to read mode

char   c   = pb.GetChar();
short  s   = pb.GetShort();
int    i   = pb.GetInt();
long   l   = pb.GetLong();
float  f   = pb.GetFloat();
double d   = pb.GetDouble();
ushort us  = pb.GetUnsignedShort();
string str = pb.GetUTF();

Type-tagged values

PrimitiveBag defines constants for a simple type-tagging scheme:

Constant Value
UNKNOWN_TYPE 0
BOOLEAN_TYPE 4
CHAR_TYPE 5
FLOAT_TYPE 6
DOUBLE_TYPE 7
BYTE_TYPE 8
SHORT_TYPE 9
INT_TYPE 10
LONG_TYPE 11

Building and parsing a binary packet

// Serialize
var pb = new PrimitiveBag();
pb.PutInt(1);           // record type
pb.PutUTF("Alice");     // name
pb.PutLong(42L);        // value

byte[] packet = pb.Bytes;

// Deserialize
var reader = new PrimitiveBag(packet);
reader.Flip();
int    type  = reader.GetInt();
string name  = reader.GetUTF();
long   value = reader.GetLong();

TextManager

TextManager stores characters (char) rather than bytes, making it the preferred container for in-memory text manipulation. It mirrors the ByteBag position/limit/mark model and exposes a full StringBuilder-compatible API alongside TextReader and TextWriter access.

Constructors

var tm = new TextManager();                   // default capacity (1000 chars)
var tm = new TextManager(8192);               // specified capacity
var tm = new TextManager(charArray);          // wrap a char array
var tm = new TextManager("initial content");  // initialize from a string

Writing text

var tm = new TextManager();

tm.Put('H');
tm.Put(charArray, 0, charArray.Length);
tm.Append("Hello, ");
tm.Append(42);                                // any primitive type
tm.AppendLine("world");
tm.AppendFormat("x={0}, y={1}", 10, 20);
tm.Insert(0, "PREFIX:");
tm.Replace("old", "new");
tm.Remove(5, 3);                             // remove 3 chars at index 5
tm.Delete(10, 20);                           // remove chars in range [10, 20)

Reading text

tm.Flip();
char   ch  = tm.Get();
string str = tm.ToString();                  // snapshot without needing Flip

tm.Rewind();
string line = tm.Reader.ReadLine();

File I/O

var tm = new TextManager();
tm.Load(new FileInfo(@"C:\docs\notes.txt"));

tm.AppendLine("-- appended note --");

tm.Save();                                        // save to the loaded path
tm.Save(new FileInfo(@"C:\docs\notes_v2.txt"));   // save to a new path

TextReader and TextWriter access

var tm = new TextManager();
tm.Writer.WriteLine("written via TextWriter");

tm.Flip();
string all = tm.Reader.ReadToEnd();

Useful properties

Property Type Description
Length long Number of characters currently stored
Position long Current read/write cursor
Available long Characters remaining to read
Capacity int Size of the backing char array
Characters char[] Snapshot copy of stored characters
Name string Optional label or file path
Encoding Encoding Encoding used for file I/O
Reader TextReader Cached TextManagerReader (no close required)
Writer TextWriter Cached TextManagerWriter (no close required)
MovementBufferSize int Buffer size for stream transfers (default: 8192)
this[int index] char Direct indexed access to individual characters

Exception Types

Type When thrown
ByteBagException Base class; thrown for general ByteBag errors
BagUnderflowException A Get or typed read operation requests more data than Available
BagDataFormatException Data is structurally invalid (e.g., malformed UTF-8 in GetUTF)
try
{
    byte b = bag.Get();
}
catch (BagUnderflowException)
{
    // handle exhausted buffer
}
catch (BagDataFormatException)
{
    // handle corrupt data
}

NuGet Package

The library is distributed as a multi-target NuGet package. Add it to your project with:

dotnet add package SRO.IO.DataBag

or via the Visual Studio NuGet Package Manager UI.


License

Copyright © 2014 Serengeti Research Organization

Showing the top 20 packages that depend on SRO.IO.DataBag.

Packages Downloads
SRO.CLSJVM.LookingGlass
Looking Glass - A view from one Binary World to Another : The LookingGlass project is a research project that has been built from the bottom up to provide the facility to create JVM (Java Virtual Machine) class files (the JVM binary format) from within the .NET framework. This may seem to be a very useless project for some people but its features may be the foundation some amazing projects. This part of the Looking Glass project is a higher level abstraction of some of the class file editing. It is easier to use than some of the other parts of the API.
7
SRO.CLSJVM.LookingGlass
Looking Glass - A view from one Binary World to Another : The LookingGlass project is a research project that has been built from the bottom up to provide the facility to create JVM (Java Virtual Machine) class files (the JVM binary format) from within the .NET framework. This may seem to be a very useless project for some people but its features may be the foundation some amazing projects. This part of the Looking Glass project is a higher level abstraction of some of the class file editing. It is easier to use than some of the other parts of the API.
6
SRO.CLSJVM.LookingGlass
Looking Glass - A view from one Binary World to Another : The LookingGlass project is a research project that has been built from the bottom up to provide the facility to create JVM (Java Virtual Machine) class files (the JVM binary format) from within the .NET framework. This may seem to be a very useless project for some people but its features may be the foundation some amazing projects. This part of the Looking Glass project is a higher level abstraction of some of the class file editing. It is easier to use than some of the other parts of the API.
5
SRO.CLSJVM.LookingGlass
Looking Glass - A view from one Binary World to Another : The LookingGlass project is a research project that has been built from the bottom up to provide the facility to create JVM (Java Virtual Machine) class files (the JVM binary format) from within the .NET framework. This may seem to be a very useless project for some people but its features may be the foundation some amazing projects. This part of the Looking Glass project is a higher level abstraction of some of the class file editing. It is easier to use than some of the other parts of the API.
4
SRO.CLSJVM.LookingGlass
Looking Glass - A view from one Binary World to Another : The LookingGlass project is a research project that has been built from the bottom up to provide the facility to create JVM (Java Virtual Machine) class files (the JVM binary format) from within the .NET framework. This may seem to be a very useless project for some people but its features may be the foundation some amazing projects. This part of the Looking Glass project is a higher level abstraction of some of the class file editing. It is easier to use than some of the other parts of the API.
3

.NET Framework 4.7.2

  • No dependencies.

.NET Framework 4.8

  • No dependencies.

.NET 8.0

  • No dependencies.

.NET 9.0

  • No dependencies.

.NET Standard 2.0

  • No dependencies.

.NET Standard 2.1

  • No dependencies.

Version Downloads Last updated
1.0.1 9 09/02/2026