The Storage Kit: BResources

The Storage Kit Table of Contents | The Storage Kit Index

# BResources

Derived from: none

Declared in: be/storage/Resources.h

Library: libbe.so

You may not want to be here...The BResources class was designed for a specific purpose: To provide a means to bundle application "resources" (icons, in particular) within the application executable itself. If you want to add new resources to your own application (resources that you want to have "stick" to the executable), then you've come to the right place. But you shouldn't use BResources to add data to a regular data file—use attributes instead.

###### Summary

The data that a file contains is either "flat," or it's "structured." To read a flat file, you simply open it (through a BFile object) and start `Read()`'ing. Structured data requires that you understand the structure. Typically, an application understands the structure either because it's a well-known format, or because the application itself wrote the file in the first place.

The BResources class defines a simple design for storing structured data. The structure is a series of "resources," where each resource is key/value pair. A single "resource file" can hold an unlimited number of resources; a single resource within a resource file can contain an unlimited amount of data.

Resources are sort of like attributes in that they store chunks of data that are looked up through the use of a key. But note these differences:

- Resources are stored in the file itself, such that if you copy the file, you copy the resources, as well.

- Resources can't be queried.

- Only plain files can have resources. (In other words, directories and symbolic links can't have resources.)

### Initializing a BResources Object

The BResources class provides the means for reading and writing a file's resources, but it doesn't let you access the file directly. Instead, you must initialize the BResources object by passing it a valid BFile object, either in the constructor or the `SetTo()` function. Note the following:

- The BFile that you pass in is copied by the BResources object. Thus, initializing a BResources object opens a new file descriptor into the file. You can delete the "original" BFile immediately after you use it to initialize the BResources object.

- Care must be taken to avoid writing to a BFile that other applications have open for reading. BResources can't enforce this rule, but if you're not careful to abide by it, problems can (and will) occur. Likewise, multiple applications mustn't open the same file for writing at the same time.

- If you want to write resources, the BFile must not be locked when you pass it in. The BResources needs to be able to lock its copy of your object.

- The BFile must be open for reading (at least).

- Unfortunately, BResources lacks an `InitCheck()` function. If you want to check initialization errors, you should always initialize through `SetTo()`, rather than through the constructor.

#### Identifying and Creating Resource Files

You can't use just any old file as a BResources initializer: The file must be an actual resource file. Simply initializing a BResources object with an existing non-resource file will not transform the file into a resource file—unless you tell the initializer to clobber the existing file.

For example, this initialization fails:

       /* "fido" exists, but isn>t a resource file. */
       BFile file("/boot/home/fido", B_READ_WRITE);
       BResources res;
       status_t err;

       if ((err = res.SetTo(&file)) != B_OK)
       ...

And this one succeeds...

       /* The second arg to SetTo() is the "clobber?" flag. */
       if ((err = res.SetTo(&file, true)) != B_OK)
       ...

...but at a price: fido's existing data is destroyed (truncated to 0 bytes), and a new "resource header" is written to the file. Having gained a resource header, fido can thereafter be used to initialize a BResources object.

Clobber-setting a resource file is possible, but, as mentioned at the top of this class description, you'll probably never create resource files directly yourself

So where do resource files come from if you don't create them yourself? Step right up...

#### Executables as Resource Files

The only files that are naturally resource-ful are application executables. For example, here we initialize a BResources object with the IconWorld executable:

       BPath path;
       BFile file;
       BResources res;

       find_directory(B_APPS_DIRECTORY, &path);
       path.Append("IconWorld");
       file.SetTo(&path, B_READ_ONLY);

       if (res.SetTo(&file) != B_OK)
          ...

The BResources object is now primed to look at IconWorld's resources. But be aware that an application's "app-like" resources (its icons, signature, app flags) should be accessed through the BAppFileInfo class.

### Resource Data

After you've initialized your BResources object, you use the Fiddle`Resource()` functions to examine and manipulate the file's resources:

#### Generative Functions

- `AddResource()` adds a new resource to the file.

- `RemoveResource()` removes an existing resource from the file.

#### Data Function

- `LoadResource()` loads a resource from disk and returns a pointer to it.

#### Info Functions

- `HasResource()` tells you if the file contains a specified resource.

- `GetResourceInfo()` returns information about a resource.

As mentioned earlier, the BFile that you use to initialize a BResources object must be open for reading. If you also want to modify the resources (by adding, removing, or writing) the BFile must also be open for writing.

#### Identifying a Resource within a Resource File

A single resource within a resource file is tagged with a data type, an ID, and a name:

- The data type is one of the `type_code` types (`B_INT32_TYPE`, `B_STRING_TYPE`, and so on) that characterize different types of data. The data type that you assign to a resource doesn't restrict the type of data that the resource can contain, it simply serves as a way to label the type of data that you're putting into the resource so you'll know how to cast it when you retrieve it.

- The ID is an arbitrary integer that you invent yourself. It need only be meaningful to the application that uses the resource file.

- The name is optional, but can be useful: You can look up a resource by its name, if it has one.

Taken singly, none of these tags needs to be unique: Any number of resources (within the same file) can have the same data type, ID, or name. It's the combination of the data type constant and the ID that uniquely identifies a resource within a file. The name, on the other hand, is more of a convenience; it never needs to be unique when combined with the data type or with the ID.

Some functions also provide the option to use a pointer to a resource's data to identify the resource; once a resource has been loaded into memory by calling `LoadResource()`, you can use the resulting pointer to identify it.

#### Data Format

All resource data is assumed to be "raw": If you want to store a `NULL`-terminated string in a resource, for example, you have to write the `NULL` as part of the string data, or the application that reads the resource from the resource must apply the `NULL` itself. Put more generally, the data in a resource doesn't assume any particular structure or format, it's simply a vector of bytes.

#### Data Ownership

Resource data that you retrieve from a BResources object belongs to the BResources object. You mustn't `free()` these pointers.

Individual changes that you make to the resource file are cached in memory until you call the `Sync()` function. Other applications won't see the changes until then.

### Reading and Writing a Resource File as a Plain File

Just because a file is a resource file, that doesn't mean that you're prevented from reading and writing it as a plain file (through the BFile object). For example, it's possible to create a resource file, add some resources to it, and then use a BFile object to seek to the end of the file and write some flat data. But you have to keep track of the "data map" yourself—if you go back and add more resources to the file (or extend the size of the existing ones), your flat data will be overwritten: The BResources object doesn't preserve non-resource data that lives in the file that it's operating on.

## Constructor and Destructor

### BResources()

`BResources(`void`) `
`BResources(` BFile *file, bool clobber = false`) `

Creates a new BResources object. You can initialize the object by passing a pointer to a valid BFile; without the argument, the object won't refer to a file until `SetTo()` is called.

If clobber is true, the file that's referred to by BFile is truncated (it's data is erased), and a new resource file header is written to the file. If clobber is false and the file doesn't otherwise doesn't have a resource header, the initialization fails.

BResources copies the BFile argument; after the constructor returns, you can, for example, delete the BFile that you passed in.

### ~BResources()

virtual `~BResources() `

Destroys the BResources object.

## Member Functions

### AddResource()

status_t `AddResource(`type_code type,
int32 id,
const void *data,
size_t length`,
` const char *name`= NULL``)

`

Adds a new resource to the file. For this function to have an effect, the file must be open for writing. The arguments are:

- type is one of the `type_code` constants defined in be/support/TypeConstants.h.

- id is the ID number that you want to assign to the resource. The value of the ID has no meaning other than that which your application gives it; the only restriction on the ID is that the combination of it and the data type constant must be unique across all resources in this resource file.

- data is a pointer to the data that you want the resource to hold.

- length is the length of the data buffer, in bytes.

- name is optional, and needn't be unique. Or even interesting.

Ownership of the data pointer isn't assigned to the BResources object by this function; after `AddResource()` returns, your application can free or otherwise manipulate the buffer that data points to without affecting the data that was written to the file.

RETURN CODES

- `B_OK`. The resource was successfully added.

- `B_NOT_ALLOWED`. The is open read-only.

- `B_FILE_ERROR`. The file's resource map doesn't exist or is invalid.

- `B_BAD_VALUE`. The data pointer is `NULL`.

- `B_NO_MEMORY`. Not enough memory to add the resource to the file.

### File()

const BFile &`File(`void`)` const` `

Returns the BFile the BResource object references.

### GetResourceInfo()

bool `GetResourceInfo(`int32 byIndex,
type_code *typeFound,
int32 *idFound,
const char **nameFound,
size_t *lengthFound`)

`

bool `GetResourceInfo(`type_code byType,
int32 andIndex,
int32 *idFound,
const char **nameFound,
size_t *lengthFound`)

`

bool `GetResourceInfo(`type_code byType, int32 andId, const char **nameFound, size_t *lengthFound`) `
bool `GetResourceInfo(`type_code byType, const char *andName, int32 *idFound, size_t *lengthFound`) `

bool `GetResourceInfo(`const void *byPointer
type_code *typeFound,
int32 *idFound,
size_t *lengthFound
const char **nameFound`)

`

These functions return information about a specific resource, as identified by the first one or two arguments:

- The first version (byIndex) searches for the byIndex'th resource in the file.

- The second (byType/andIndex) searches for the byIndex'th resource that has the given type.

- The third (byType/andId) looks for the resource with the unique combination of type and ID.

- The fourth (byType/andName) looks for the first resource that has the given type and name.

- The last (byPointer) returns information about the resource whose data is pointed to by byPointer. This can be used to trace a resource that's already been loaded with `LoadResource()` back to its information.

The other arguments return the other statistics about the resource (if found).

The pointer that's returned in *foundName belongs to the BResources. Don't free it.

The functions return `true` if a resource was found, and `false` otherwise.

### HasResource()

bool `HasResource(`type_code type, int32 id`) `
bool `HasResource(`type_code type, const char *name`) `

Returns `true` if the resource file contains a resource as identified by the arguments, otherwise it returns `false`.

Keep in mind that there may be more than one resource in the file with the same name and type combination. The type and id combo, on the other hand, is unique. See "Identifying a Resource within a Resource File."

### LoadResource()

const void *`LoadResource(`type_code type, int32 id, size_t *outSize`) `
const void *`LoadResource(`type_code type, const char *name, size_t *outSize`) `

Loads the specified resource into memory. The resource can be identified by either type code and ID or by type code and name. See "Identifying a Resource within a Resource File."

The returned pointer belongs to the resource file; it's valid until the resource gets changed. If an error occurs while trying to load the resource, `NULL` is returned.

### MergeFrom()

status_t `MergeFrom(` BFile *fromFile`) `

Copies all the resource from the file specified by fromFile into the file targeted by the BResources object. The original file isn't changed. You can do this to a file that's opened read-only, but the changes won't have any effect.

RETURN CODES

`B_OK`. The resources were copied without error.

- `B_BAD_FILE`. The resource map is empty.

- `B_FILE_ERROR`. A file error occurred, or the resource map is nonexistent.

- `B_IO_ERROR`. An error occurred while writing the data.

- `B_ERROR`. Something else went wrong.

### PreloadResourceType()

status_t `PreloadResourceType(`type_code type = 0`) `

If you know you're going to need to access all resources of a particular type, you can preload them all into memory in one shot using this function. If you specify a type of 0, all resources of all types are preloaded.

RETURN CODES

`B_OK`. The resources were preloaded without error.

- `B_BAD_FILE`. The resource map is empty.

- Other values. The returned value is the negative of the number of errors that occurred while preloading resources; for example, if five errors occurred, the result is -5.

### RemoveResource()

status_t `RemoveResource(`type_code type, int32 id`) `
status_t `RemoveResource(`const void *resource`) `

Removes the resource identified by the arguments. See "Identifying a Resource within a Resource File."

RETURN CODES

- `B_OK`. The resource was removed.

- `B_FILE_ERROR`. The file's resource map doesn't exist.

- `B_NOT_ALLOWED`. The file is opened read-only.

- `B_BAD_VALUE`. Couldn't find the specified resource, or an error occurred trying to remove it (first form of `RemoveResource()`).

- `B_ERROR`. Couldn't find the specified resource, the pointer doesn't indicate a valid resource, or an error occurred while removing the resource (second form).

### SetTo()

status_t `SetTo(` BFile *file, bool clobber = false`) `

Unlocks and closes the object's previous BFile, and re-initializes it to refer to a copy of the argument. If the new BFile is open for writing, the BResources' copy of the BFile is locked.

If clobber is `true`, the file that's referred to by BFile is truncated (it's data is erased), and a new resource file header is written to the file. If clobber is `false` and the file doesn't otherwise doesn't have a resource header, the initialization fails.

RETURN CODES

- `B_OK`. The resource was removed.

- `B_BAD_VALUE`. The argument BFile is invalid (uninitialized).

- `B_ERROR`. The BResources couldn't be initialized (for whatever reason).

### Sync()

status_t `Sync(`void`) `

Updates all changed resources on disk. This actually rewrites the entire resource file, so be aware of this when designing your code. This is a very good reason not to use BResources for anything other than permanent, nonchanging application data, and only developer tools should write to resource files.

RETURN CODES

`B_OK`. The resources were updated without error.

- `B_BAD_FILE`. The resource map is empty.

- `B_NOT_ALLOWED`. The file is opened read-only.

- `B_FILE_ERROR`. A file error occurred.

- `B_IO_ERROR`. An error occurred while writing the data.

### WriteTo()

status_t `WriteTo(` BFile *newFile`) `

Writes all the file's resources into a new file. After this function returns, the BResources object is targeted on the new BFile; all future operations will be done in the new file.

RETURN CODES

`B_OK`. The resources were written without error.

- Other errors. File errors indicating problems copying the data.

The Storage Kit Table of Contents | The Storage Kit Index

The Be Book,
...in lovely HTML...
for BeOS Release 5.

Copyright © 2000 Be, Inc. All rights reserved..