Skip to content
Haiku OSDeep Dive Published Updated 6 min readViews unavailable

Haiku BResources: Packaging Typed Data Inside Executables

How Haiku stores typed resources in files, exposes them through BResources, mirrors application metadata with BAppFileInfo, and avoids destructive update mistakes.

Haiku can store typed resource data inside an ordinary file, including an application executable. Icons, interface archives, localized strings, cursors, and other compact assets can travel with the binary instead of living in a parallel directory tree. The Storage Kit exposes those entries through BResources, while BAppFileInfo gives application metadata such as signature, flags, version information, and icons a higher-level interface.

Resources are convenient packaging, not a miniature searchable filesystem. They are opaque byte values addressed through a type and numeric ID, optionally accompanied by a name. Choosing the right API and update workflow matters because an incautious resource write can clobber a file or invalidate data appended by another tool.

A type and ID form the resource key

Every resource has a type_code and an integer ID. That pair uniquely identifies it within the file. A name can improve diagnostics and authoring, but names are optional and need not be unique, so runtime lookup should not treat a display name as a primary key unless the application controls the entire format.

The resource payload is raw bytes. It may contain a flattened BMessage, a bitmap representation, text, or a private structure, but BResources does not infer that schema. Store a format version in structured payloads and decode fixed-width values carefully if files may cross architectures or application versions.

Resource type constants document intent. Reusing one type for unrelated layouts makes later inspection ambiguous. Keep IDs stable once consumers or add-ons depend on them, and reserve ranges when multiple components contribute resources to one executable.

Initialize without accidentally erasing the file

A BResources object can be associated with an open BFile. The Haiku documentation recommends using SetTo() because constructors do not offer an InitCheck() method for independently verifying initialization. Always inspect the returned status_t before loading or modifying data.

The clobber argument is especially important. If a target is not already a resource file, setting clobber to true permits the resource system to truncate its prior contents. That can be intentional for a dedicated .rsrc artifact and catastrophic for an executable or document.

BFile file(path, B_READ_WRITE);
status_t openStatus = file.InitCheck();
if (openStatus != B_OK)
    return openStatus;

BResources resources;
status_t resourceStatus = resources.SetTo(&file, false);
if (resourceStatus != B_OK)
    return resourceStatus;

The example refuses to clobber a non-resource file. A build step that creates a fresh resource container can make a different explicit choice, but it should write to a temporary path and atomically replace the output only after every operation succeeds.

Loaded data belongs to BResources

LoadResource() returns a pointer managed by the BResources object. The caller must not free it, and the pointer should be treated as invalid after operations that replace resources, change the associated file, or destroy the object. Copy the bytes into application-owned storage when their lifetime must extend beyond the resource object.

Validate both the returned pointer and reported size before decoding. A type and ID match proves which entry was selected, not that the payload is complete or semantically valid. A malformed flattened message or image must fail at its own parser boundary.

Changes are cached. Call Sync() and check its return value before treating an update as durable. Closing a build process without checking the final write converts storage errors into silently incomplete application artifacts.

Avoid concurrent writers and trailing-data assumptions

The resource documentation warns against concurrent modification through multiple BResources objects. There is no transaction that merges independent edits. Serialize writers or create a complete new artifact from controlled inputs.

Resource data is associated with a plain file and can coexist with ordinary file content, which is why executables can carry resources. But data another tool appends after the resource area is not safe merely because it appears after the current end. A later resource modification may overwrite that trailing data as the resource layout changes.

Do not invent a binary format by appending an unrelated signature or payload after an executable’s resources. If two formats must coexist, use a documented container or separate file and test every authoring tool in the pipeline.

Use BAppFileInfo for application identity

An executable’s signature, supported types, app flags, versions, and icons have system-wide meaning. BAppFileInfo reads and writes these properties using the representations expected by Haiku. By default it can work with both filesystem attributes and embedded resources, allowing application metadata to remain available in contexts where one representation is preferred.

This mirroring is not a reason to hand-edit both copies independently. Choose BAppFileInfo as the authoritative writer, check every status, then query the installed artifact as Tracker and the registrar will see it. A stale attribute and a fresh resource can otherwise produce inconsistent behavior depending on which interface reads first.

Use BResources directly for application-specific assets that do not have a dedicated higher-level API. This preserves the semantic validation and naming conventions built into BAppFileInfo for the fields it owns.

Compile resources as a reproducible build input

Haiku provides rc as a resource compiler and xres to list and manipulate resources. Keep the resource definition or original assets in version control, then generate the final resource payload as part of the build. Treat manual post-build edits as debugging, not as the release process.

A repeatable pipeline can:

  1. Compile source and link the executable.
  2. Compile declared resources with rc.
  3. Attach or merge resources using the supported tools.
  4. Write application metadata through the appropriate build tooling.
  5. List the final resource table with xres.
  6. Launch a smoke test that loads every mandatory type and ID.
  7. Package only after all status checks pass.

Compare a clean rebuild byte-for-byte where the toolchain permits it, or at least compare the enumerated type, ID, name, size, and decoded version of every resource. That catches an accidental developer-machine asset and an ID collision before distribution.

Design resources for replacement and recovery

An update should never modify the only release artifact in place. Copy or rebuild to a temporary file, apply resource changes, call Sync(), close the file, reopen it read-only, and validate every required entry. Then replace the destination atomically and preserve the previous version until launch succeeds.

Resource lookup failures deserve specific diagnostics: file open status, resource type, ID, expected format version, and actual size. Do not dump arbitrary payload bytes because a resource can contain user or licensing data. If an optional asset is missing, select a deliberate fallback. If an identity or executable-critical resource is invalid, fail the build or launch rather than running in a partially branded state.

Embedded resources make a Haiku application self-contained when their keys and schemas are stable and the build is reproducible. BResources supplies storage mechanics; it does not provide concurrent update safety, schema validation, or rollback. Those guarantees belong in the pipeline that creates and tests the executable.

Related:

Sources:

Comments