Bodu.IO.Compound
1.0.0
dotnet add package Bodu.IO.Compound --version 1.0.0
NuGet\Install-Package Bodu.IO.Compound -Version 1.0.0
<PackageReference Include="Bodu.IO.Compound" Version="1.0.0" />
<PackageVersion Include="Bodu.IO.Compound" Version="1.0.0" />
<PackageReference Include="Bodu.IO.Compound" />
paket add Bodu.IO.Compound --version 1.0.0
#r "nuget: Bodu.IO.Compound, 1.0.0"
#:package Bodu.IO.Compound@1.0.0
#addin nuget:?package=Bodu.IO.Compound&version=1.0.0
#tool nuget:?package=Bodu.IO.Compound&version=1.0.0
Bodu.IO.Compound
API stability — Stable. The public API surface is committed; breaking changes are reserved for a major-version bump per SemVer.
A small, dependency-free reader, editor, and writer for the OLE2 / Compound File Binary
(CFB) container format — the structured-storage envelope behind legacy Microsoft Office
files such as .xls, .doc, .ppt, and .msg.
It understands the container: it navigates the storage hierarchy, exposes the metadata of every entry, materializes the bytes of any named stream, edits existing containers transactionally, authors new ones, and reads and writes OLE property sets (summary information). It applies no interpretation to application stream contents — turning those bytes into a workbook, a document, or anything else is the consumer's job.
using Bodu.IO.Compound;
using var file = CompoundFile.Open(stream);
// Navigate the storage hierarchy (the IStorage / IStream model).
foreach (CompoundEntryInfo entry in file.RootStorage.EnumerateEntries())
Console.WriteLine($"{entry.Name} ({entry.EntryType}, {entry.Length} bytes, clsid {entry.ClassId})");
if (file.RootStorage.TryOpenStream("Workbook", out CompoundStream? workbook))
{
using (workbook)
ProcessWorkbook(workbook.ReadAllBytes()); // or use workbook as a Stream
}
// Read document metadata from the OLE property sets.
if (file.TryGetSummaryInformation(out var summary))
Console.WriteLine($"{summary.Title} by {summary.Author}, created {summary.CreateTime}");
Capabilities
- Header, sector-size, and signature validation;
CompoundFile.IsCompoundFilefor a non-destructive signature probe. - Open from a
Stream(CompoundFile.Open) or a path (CompoundFile.OpenRead(path)), with span- and async-capable per-stream reads (CompoundStream.Read(Span<byte>)/ReadAsync). - Regular FAT traversal (including extended DIFAT sectors) and mini-FAT / mini-stream resolution, with cycle and out-of-range detection.
- A navigable storage hierarchy (
CompoundStorage/CompoundStream) with child lookups scoped per storage — the managed counterpart of COMIStorage/IStream.CompoundFile.Open/CompoundStorage.OpenStreamaccept BCLFileMode/FileAccess, mirroringSystem.IO.Packaging. - A unified, package-aligned write API:
CompoundFile.Create(stream)/Create(path)starts a new file, andCompoundFile.Open(stream, FileMode.Open, FileAccess.ReadWrite)loads an existing one for update. The writableRootStorageexposesCreateStorage/CreateStream/Delete/Rename, a writableCompoundStream(payloads up toint.MaxValue; larger streams go through the deferred builder sources), and settable entry metadata (ClassId/CreationTime/ModifiedTime/StateBits) on a storage. Edits are staged in memory and written to the destination only whenCommit()— or the asynchronousCommitAsync/FlushAsync— is called;Revert()discards them and disposing without committing leaves the destination untouched. - Bounded-memory streaming reads:
CompoundFile.Open(stream, buffered: false)reads sectors on demand from a seekable stream, andCompoundStorage.OpenStream(name)returns a lazyCompoundStreamfor large streams, so a multi-gigabyte file can be read without buffering it whole.CompoundStorageBuilder.FromFile(file, lazy: true)reads into deferred nodes for a fully streamed read → re-save copy. - Tunable open behavior via
CompoundFileOptions(CompoundFile.Open(stream, options)): aCompoundReadStrategy(Buffered/Streaming/Autowith aMaxBufferedBytesthreshold) and aCompoundValidationLevel—Strictrejects malformed directory entries the default tolerates, the defaultCompatiblematches the historical behavior, andMinimalrecovers from cyclic / out-of-range / short sector chains by returning the bytes read so far. - Per-entry metadata via
CompoundEntryInfo(theSTATSTGanalogue): class id, state bits, creation / modified time stamps, and red-black node color — readable on any entry and settable on a writable storage (see the write API above).CompoundStream.Parent/CompoundStorage.Parentgive upward navigation, and every exception derives fromCompoundFileException. - OLE property-set parsing and writing (
Bodu.IO.Compound.PropertySets):OlePropertySet/OlePropertyValue(PROPVARIANT, including vector values) plus the strongly-typedSummaryInformation/DocumentSummaryInformationviews and…Builderauthors, including user-defined custom properties. On a writable file,CompoundFile.SetSummaryInformation/SetDocumentSummaryInformationandCompoundStorage.WritePropertySetembed a set as the read counterparts ofTryGet…/TryOpenPropertySet. - A detached snapshot-authoring model,
CompoundStorageBuilder: build a JsonNode-style tree ofCompoundStorageBuilder/CompoundStreamBuilderchildren withCompoundStorageBuilder.CreateRoot()(orCompoundStorageBuilder.Loadan existing file into one), thenWriteTo/Save/ToArrayto a conforming container (v3 or v4). Output is verified byte-for-byte and cross-checked against the independentolefileand OpenMcdf parsers. (For live read/write useCompoundFile.) - Bounded-memory streaming writes:
CompoundStorageBuilder.WriteTo(Stream)emits one sector at a time and large payloads can be sourced on demand viaCompoundStreamBuilder.CreateFromFile(name, path)orCreate(name, Func<Stream>, length)(and the matchingCompoundStorageBuilder.AddStreamFromFile), so multi-gigabyte containers serialize without being buffered whole in memory. - Stable, message-independent failure classification through
CompoundFileFormatException.Category(CompoundFileError) and aCompoundFileSerializationExceptionfor authoring errors.
using Bodu.IO.Compound;
using Bodu.IO.Compound.Builders;
using Bodu.IO.Compound.PropertySets;
var builder = CompoundStorageBuilder.CreateRoot();
builder.AddStorage("Storage 1").AddStream("Stream 1", new byte[] { 1, 2, 3 });
builder.AddStream(SummaryInformation.StreamName,
new SummaryInformationBuilder { Title = "Report", Author = "Ada" }.ToArray());
builder.WriteTo(stream); // writes an OLE2 / CFB file
Runnable samples
The repository ships an offline, dotnet run-able sample for this package — builder-based
authoring with byte-exact read-back, OLE property sets on authored and real Word files,
signature detection with the v3/v4 version knob, and walking a real .doc's storage tree —
under samples/IO.Compound/.
Out of scope
Both creating and updating rebuild the whole container: Commit() serializes the entire staged tree
and rewrites the destination from scratch. Incremental in-place editing that rewrites only the changed
sectors of an existing file (the COM IStorage/Commit transacted model), encryption, and
damaged-file recovery remain out of scope.
Part of the Bodu utility library.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
NuGet packages (2)
Showing the top 2 NuGet packages that depend on Bodu.IO.Compound:
| Package | Downloads |
|---|---|
|
Bodu.Formats.Excel.Binary
A narrow, read-only reader for the Excel binary workbook format (.xls): BIFF8 as written by Excel 97-2003 and BIFF5 as written by Excel 5.0/95. Exposes the raw cell values of a worksheet — strings, numbers, booleans, and errors, including the cached result of a formula cell — along with each cell's number format and date-format detection, the workbook date system, each sheet's declared used range, and the workbook document properties. Offers both a streaming cell surface and a materialized, randomly addressable worksheet view, without formula evaluation, styling, or any higher-level interpretation. Built on Bodu.IO.Compound for the container and Bodu.IO.Biff for the record stream. |
|
|
Bodu.Formats.Outlook.Msg
A read-only reader for the Outlook message format (.msg / MS-OXMSG) over the Bodu.IO.Compound OLE2 container. Opens a message as a disposable session exposing every decoded MAPI property, the recipient and attachment tables, nested attached messages, named-property resolution, and the text, HTML, and compressed-RTF bodies — without any MAPI session emulation or message authoring. Shares the Bodu.Formats.Outlook MAPI value model. |
GitHub repositories
This package is not used by any popular GitHub repositories.