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 |