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

Haiku BResourceStrings: Read-Only String Resources and Pointer Lifetime

Use Haiku BResourceStrings to read CSTR resources by ID while managing file selection, borrowed pointers, reloads, and locale fallback explicitly.

BResourceStrings is a convenience class for reading string resources from an application or another resource file. It loads resources of the CSTR type and makes them available by numeric ID through FindString() or NewString(). It is a fast read-only lookup helper, not a locale-selection engine, translator catalog manager, or automatic fallback system.

The API’s scope matters in a localized application. BResourceStrings reads the file you select; it does not decide which language should be active, select a catalog based on the user’s locale, or merge fallbacks. Haiku’s Locale Kit and the application’s resource packaging policy remain responsible for those choices. A resource ID is a stable lookup key only if the build process and source maintain that mapping consistently.

Select and validate the resource file

The default constructor initializes from the application file. The entry_ref constructor selects a specific resource file. SetStringFile() can switch the source later, and passing a null reference returns to the application resource file according to the implementation. Check InitCheck() after construction or switching. An inaccessible file, missing resource, or failed allocation means lookups cannot be trusted.

BResourceStrings strings;
status_t status = strings.InitCheck();
if (status != B_OK)
    return status;

const char* text = strings.FindString(kWelcomeText);
if (text == NULL)
    return B_ENTRY_NOT_FOUND;

BString stableCopy(text);

The ID kWelcomeText is application-defined. Define IDs in one source-controlled header and avoid reusing an ID for a different meaning. FindString() returns a borrowed pointer owned by the BResourceStrings object. Copy it into an application-owned value if it must survive a resource reload, file switch, or object destruction.

NewString() returns a newly allocated BString* that the caller must delete. Use it when the caller needs an owned result and can manage the allocation. For a hot UI path, FindString() avoids allocating a new BString, but its lifetime must be respected. Do not store either result in a long-lived model without documenting who owns it.

Treat FindString() pointers as borrowed

The reference documentation says the pointer remains valid until the object is destroyed or set to another file. That means a UI can use it while the resource source stays fixed, but a concurrent SetStringFile() can invalidate the pointer. The implementation locks during lookup and returns the internal string after releasing its lock; callers need external coordination if one thread can switch files while another uses returned pointers.

Use one of three explicit strategies. Keep the resource file immutable for the entire object lifetime; copy strings under a coordinated reload protocol; or serialize lookup and file switching on one owner thread. Do not assume the internal lock protects the caller’s subsequent use of a returned pointer.

When switching files, update dependent views only after the new object reports successful initialization. If the switch fails, choose whether to retain the old language resources or show a clear fallback; do not expose half-loaded strings. Since the method can clear current state before attempting the new file, preserve an independent reference or copied snapshot if rollback is required.

Keep resource IDs and localization policy separate

BResourceStrings::RESOURCE_TYPE is CSTR. IDs identify individual resources in that type. Resource names, if present in the resource file, do not replace the ID lookup contract of this class. Keep string IDs generated or reviewed alongside the resource compiler input so that a renamed string does not accidentally become an unrelated ID.

Do not use resource IDs as user-facing text, database keys, or file format fields. They are packaging-level identifiers. For persistent user data, store a semantic key or schema value instead. For a localized UI, route formatting through the locale-aware APIs for dates, numbers, and plural rules rather than assembling translated fragments from several CSTR resources.

Text encoding and formatting remain application responsibilities. Validate format strings before using them with printf-style calls, and prefer APIs that support typed arguments when translation can reorder placeholders. Avoid constructing a sentence by concatenating fragments whose grammar varies across languages. Include context for translators and ensure each resource has a meaningful fallback.

Treat resource updates as application releases. If a resource file is replaced while a process is running, an existing BResourceStrings object should not be assumed to refresh automatically. Decide whether the running process keeps its current string snapshot or reinitializes during a controlled configuration change. Avoid replacing the file between lookup and copy if other threads can trigger a reload; coordinate those operations with an application lock or marshal them to one owner thread.

When packaging a resource file independently from the executable, record its version alongside the app version and validate that required IDs exist before enabling the feature. A resource mismatch should produce a startup diagnostic with the missing ID and file version, not a crash while constructing a menu. If a fallback language is supported, resolve that fallback before presenting the view so one window does not mix strings from two languages unexpectedly.

Handle missing and empty resources intentionally

FindString() returns null when the object is not initialized or the requested ID is missing. It may also return an empty string resource as a valid value. Distinguish these states if the application needs an explicit blank label. Do not dereference the result or silently replace every missing string with an empty value; that can hide packaging errors until release.

NewString() can fail allocation and also returns null when the resource is missing or the object is invalid. Check for null before using it and ensure ownership is released. Add a diagnostic that includes the ID and resource file identity without logging private user paths by default.

Resource build and verification workflow

Keep the resource compiler input, numeric ID header, and packaged executable version in sync. Test the installed application, not only a debug binary from the build tree, because resource packaging can differ between those artifacts. Include one test for each supported locale and a missing-resource test that exercises the intended fallback.

Review text resources for duplicate IDs and stale translations in CI. Validate that every string referenced by code has a corresponding resource and that retired IDs are not reassigned to new meanings while older stored data may still refer to them. Exercise placeholder formatting with longest expected values, right-to-left or reordered arguments if supported, and strings containing non-ASCII characters. Keep the resource file’s provenance visible to maintainers without embedding private user data in logs.

For support bundles, include the active locale, resource file version, and missing string IDs rather than copying every translated string into a log. This preserves enough evidence to diagnose a packaging mismatch while avoiding accidental exposure of content that may contain account-specific or user-authored text. Keep fallback selection deterministic so two launches with the same installed resources produce the same UI language.

For external resource files, verify that the reference resolves, the file contains the expected CSTR resource type, and the application’s update process replaces it atomically enough for your own policy. Do not assume that an open resource object follows a replaced file automatically; reinitialize and verify the status after replacement.

Acceptance criteria

Accept a BResourceStrings integration when initialization and lookup status are checked, IDs are stable, borrowed pointers do not outlive their source, switching is coordinated with consumers, and locale choice and fallback are handled elsewhere. Test missing, empty, and malformed packaged resources in the installed build.

BResourceStrings provides efficient read-only access by ID. It does not choose a locale, validate a translation, or make returned pointers durable across reloads.

Related:

Sources:

Comments