Table of Contents

Bodu.IO.Pst Namespace

Package

Bodu.IO.Pst

Purpose

Bodu.IO.Pst is a low-level, read-only container reader for the Outlook personal-folders format (PST / MS-PST, Unicode and ANSI formats). It reads the node database (NDB) - the header, the node and block B-trees, block data with the format's permute and cyclic content encodings decoded and checksums verified, multi-block data trees, and per-node subnode trees - and the LTP layer over it: heap-on-node, BTree-on-heap, and per-node property-context and table-context views with wire-typed values. It carries no MAPI semantics and no write support: interpreting a property as a subject or a sender is the job of the Bodu.Formats.Outlook.Pst mail-store reader layered on top, which shares the Bodu.Formats.Outlook MAPI value model with the .msg reader.

A PST file is a node-oriented database in a single file. PstFile opens it as a disposable session; every object - folders, messages, tables, internal maps - is a PstNode addressed by a 32-bit PstNodeId whose five low bits carry its PstNodeType. Payloads assemble transparently from multi-block data trees, stream through a decoded-block LRU cache, and a node's private subnode tree carries its children (a message's recipient and attachment tables, for example).

Static documentation

  • Introduction - the headline types, the layering beneath the mail-store reader, and the scenarios the library covers.
  • Core concepts - node database, NID/BID, data and subnode trees, heap-on-node, property and table contexts, validation levels.
  • Getting started - install and minimal samples for opening, enumerating, and reading.
  • Binary Formats & I/O topic overview - where the container sits beneath the format readers.

Key types

Session and nodes

  • PstFile - the disposable read session. Factories OpenRead (path / Stream) and Open(Stream, options, leaveOpen), the cheap IsPstFile probe; Format / CryptMethod, the node directory via EnumerateNodes, and lookup via GetNode / TryGetNode.
  • PstNode - one node. ReadAllBytes (buffered), OpenDataStream (a seekable read-only stream keeping one leaf block resident, bound to the session - it throws once the session is disposed), DataLength (priced without payload reads); EnumerateSubnodes / TryGetSubnode; and the LTP views ReadPropertyContext / ReadTableContext.
  • PstNodeId / PstNodeType - the 32-bit identifier (five type bits + 27-bit index) with the well-known anchors MessageStore (0x21), NameToIdMap (0x61), and RootFolder (0x122).
  • PstNodeInfo - an immutable directory snapshot: identifier, parent, payload length, and whether subnodes are present.

LTP views

  • PstPropertyContext - the node's property bag: a tag-ordered collection of PstPropertyValue entries (16-bit property identifier, raw wire type, payload resolved on access, typed accessors) with TryGetValue / GetValue, plus the streaming pair TryGetValueLength / TryOpenValueStream that prices or reads a value without materializing it.
  • PstTableContext - the node's table: PstTableColumn metadata, RowCount, streaming EnumerateRows (one matrix block resident at a time), and keyed TryGetRow. PstTableRow exposes RowId, TryGetCell, EnumerateCells, and the streaming pair TryGetCellLength / TryOpenCellStream.

Options and formats

  • PstFileOptions - ValidationLevel (PstValidationLevel: Compatible / Strict / Minimal) and the decoded-block LRU BlockCacheSize (default 256 entries; 0 disables).
  • PstFileFormat / PstCryptMethod - the header's declared variant (both Unicode and Ansi are read; the OST variant is rejected) and content encoding.

Errors

Example

using Bodu.IO.Pst;

using PstFile file = PstFile.OpenRead("archive.pst");

// The store object's raw property bag.
PstNode store = file.GetNode(PstNodeId.MessageStore);
foreach (PstPropertyValue value in store.ReadPropertyContext())
    Console.WriteLine($"0x{value.PropertyId:X4} (wire 0x{value.WireType:X4}): {value.RawData.Length} bytes");

// The root folder's hierarchy table: each row identifier is a child folder's node identifier.
var hierarchyId = new PstNodeId(PstNodeType.HierarchyTable, PstNodeId.RootFolder.Index);
if (file.TryGetNode(hierarchyId, out PstNode? table))
{
    foreach (PstTableRow row in table.ReadTableContext().EnumerateRows())
        Console.WriteLine($"child folder 0x{row.RowId:X8}");
}

Classes

PstFile

Provides a disposable, read-only session over a PST file's node database (Unicode or ANSI format): the header facts, the node directory, and per-node data and subnode access.

PstFileException

Represents an error raised while reading a PST file. Serves as the base of the library's exception hierarchy.

PstFileFormatException

Represents an error raised when a PST file's structure is malformed or fails validation.

PstFileOptions

Controls how a PstFile is opened and validated.

PstNode

Represents one node of the node database: raw access to its data payload and its subnode tree.

PstNodeInfo

Provides an immutable snapshot of a node's directory facts: its identifier, its parent, the size of its data payload, and whether it carries a subnode tree.

PstNodeNotFoundException

Represents a lookup for a node that does not exist in the file.

PstPropertyContext

Represents a node's property context (PC): the LTP property bag of 16-bit property identifiers with wire-typed values, in the manner the exploration plan sketches - format-agnostic, with no MAPI semantics.

PstTableContext

Represents a node's table context (TC): the LTP table of typed columns over identifier-keyed rows, with forward-only row enumeration and keyed row lookup - format-agnostic, with no MAPI semantics.

PstTableRow

Represents one row of a table context: the row identifier and cell access by column property identifier.

PstUnsupportedFormatException

Represents an error raised when a PST file is recognized but uses a format variant or content encoding the library does not read (the 4 KiB-page OST variant or Windows Information Protection encryption).

Structs

PstNodeId

Represents a 32-bit node identifier: five type bits in the low positions and a 27-bit index above them (MS-PST §2.2.2.1).

PstPropertyValue

Represents one property value of a property context or table-context row: the 16-bit property identifier, the raw wire type code, and the resolved little-endian payload with typed accessors over it.

PstTableColumn

Represents one column of a table context: its 16-bit property identifier, its raw wire type code, and its cell width within a row.

Enums

PstCryptMethod

Identifies how a file's external block data is encoded (the header's bCryptMethod values).

PstFileError

Categorizes the failure a PstFileException reports, so callers can distinguish a missing object from structural corruption without parsing messages.

PstFileFormat

Identifies the on-disk PST format variant, discriminated by the header's wVer field.

PstNodeType

Identifies the kind of object a node holds - the five type bits of a PstNodeId (the NID_TYPE_* values of MS-PST §2.2.2.1).

PstValidationLevel

Specifies how strictly a file's structures and checksums are validated while reading.