C/C++ Guides

Home

Using Resources in a Project

This tutorial provides an introduction to adding resources, such as images and sounds, to a MoSync application. These external files need to be added into the project, so that they can be packaged with your code and deployed to the device.

Note: new ways of organizing resources were introduced in the MoSync SDK 3.0; see: Resource Compilation.

The Resource Compiler

The resource compiler is part of MoSync's Pipe-Tool (pipe-tool.exe). When you build your application in Eclipse, the resource compiler concatenates all the resources your program needs into a file called "resources" and then it creates an index by which your program can access the resources.

When it runs, the resource compiler looks for resource list files in your project. Resource list files are files that end with the .lst extension. Each resource list file references one or more resources. You don’t have to do anything special to make this work, you just need to create a file with a .lst extension and identify in it what resources you want to be included in the final packages.

You can include any file that will be useful for your program. Typically these will be images (in .png format), sounds (in .mp3 format), and MoSync-specific formats such as .mof font files.

If you are going to be creating data at runtime, or want somewhere to store downloaded data, then the resource list file is also useful for that. You can create a placeholder resource which is going to have a handle, but doesn’t yet contain any data.

There is a full description of all of the types of data you can put into a resource file in the Resource Compiler Reference. In this tutorial we will focus on a few of the common types of resource you are likely to use.

Creating a Resource List File

To add external resources to your app, you need to add a resource list file to your project. A resource list file is a text file with the .lst extension: res.lst or similar would be a good name for it.

Create the resource list file by selecting  New > Other from the MoSync IDE's File menu.

Select MoSync Resource File from the list and click Next. Type a filename ending in ".lst" and click Finish. You’ll see the new file appear in the list of files in Project Explorer. It has an icon similar to a Pac-Man ghost. Double-click on the file to open it.

Tool tip: The Eclipse IDE can help with the syntax of writing resource list files with an Intellisense-style option list as you type. Press period (.) and you’ll see it appear.

MAHeaders.h & MAHandle

The resource compiler creates an index of resources of a special type called MAHandle. Under the hood, this is actually an int, but by giving it a special type name it is easy to see where you can use the resources.

To use a resource you’ve compiled, you need to include a reference to file MAHeaders.h which the resource compiler will create in the root of your project:

#include <MAHeaders.h>

This file is a list of C #define directives, mapping the name you’ve given to your resources to the internal index number of the resource in the compiled resources file. You can use these definitions in your code.

As an example, I’ve created a resource file with a font (which we will see later). My res.lst file contains this:

.res MYFONT
.bin
.include "pretty.mof"

and the MAHeaders.h file that the resource compiler creates contains this:

#define MYFONT 1

This means that if you’ve included MAHeaders.h in my source code, you can use the reference directly.

Font* f = new Font(MYFONT);

If you look at the documentation for Font, then the constructor is

Font(MAHandle handle);

MAHandle means the name of the resource in the resource file (MYFONT), and the MAHeaders.h file maps between the name you have given it and its index position in the resources file. Whenever you see MAHandle in the MoSync documentation, it means the name you’ve given to a resource.

Images

One of the most common types of resource you’ll want to include will be an image. This should generally be a PNG file. Some phones can handle JPEG and GIF images, but PNG has the best overall support, as well as supporting an alpha level for transparency.

To include an image, you need to declare it as a resource in the resource list file in the following way:

.res BACKGROUND_IMAGE
.image "images/BG240.png"

Note: the path to the resource cannot be absolute. Furthermore you must use either forward slashes (/) in the path or escaped backslashes (\).

When this compiles, we will have a reference to BACKGROUND_IMAGE in MAHeaders.h, and this code will create an image:

#include <MAUI/Image.h>
...
Image* i = new Image(0, 0, 100, 100, NULL, true, true,BACKGROUND_IMAGE);

This will create a new image from BG240.png, and automatically set the size correctly for the image.

Alternatively, you can set the resource on an existing Image widget.

i->setResource(BACKGROUND_IMAGE);

This is useful for animation. More on that later.

Sounds

If you want to include a sound file, then there is a specific directive for this. You need to include it as a .media (or a .umedia) file.

You also need to know the MIME type of the audio format you’ve want. You can look this up at http://www.iana.org/assignments/media-types/ but you’ll probably be using MP3 files. Not every phone will play every format (see Feature/Platform Support).

To add an MP3 file, you’ll add this declaration in a resource list file:

.res MUSIC
.media "audio/mpeg", "music.mp3"

To add a MIDI file, you’ll add:

.res MUSIC
.media "audio/midi", "music.mid"

To use the sound in your application:

maSoundPlay(MUSIC, 0, maGetDataSize(MUSIC));

The second parameter here is the offset position to start playing from, and the last parameter is the number of bytes to play. The function maGetDataSize() returns the size of a resource.

Fonts

Fonts are bitmaps fonts which are specific to the MAUI user interface library. MoSync comes supplied with a couple of examples, as well as the software (the BMFonts tool) to make your own. To use them in your application, you need to include them in a resource list file.

.res MYFONT
.bin
.include "pretty.mof"

You can then use them in your own code as follows

Font* f = new Font(MYFONT);

Other tutorials will look at fonts in much more detail.

Placeholders

Placeholders provide a reference to a resource in MAHeaders, but that resource doesn’t exist yet. You’d use this in situations where you are going to either create a resource at runtime (like an image) or download data into a resource, and you want to use that resource in several places.

For instance, if you were writing an app which downloaded an image, you could create a placeholder so you can reference it when it is available:

.res DOWNLOADEDIMAGE
.placeholder

You can then download the image to the placeholder.

ImageDownloader* dl = new ImageDownloader();
dl->beginDownloading("http://austinspad.net/img/front_batman.png", DOWNLOADEDIMAGE);

This is just an excerpt of the code required for downloading. See the Downloading Data from the Internet tutorial for more information and examples.

When this has completed downloading, you can save the image to local storage:

MAHandle imagestore = maCreateStore("IMAGESTORE", MAS_CREATE_IF_NECESSARY);
maWriteStore(imagestore, DOWNLOADEDIMAGE);
maCloseStore(imagestore, 1);

Even if you don’t save it permanently, you can still access the Image you’ve created by referencing the placeholder name you’ve used. You can use this across your whole application, and not just in the scope of the downloader.

You can also create placeholders at runtime. The difference with these is that the reference is not in MAHeaders.h, so it won’t be available to all the classes in your application.

MAHandle TEMPIMAGE = maCreatePlaceholder();

Sequential Files

Not every file has to have its own resource label. You can create a series of resources which are each accessed from the same root MAHandle. For instance, if you wanted to create an animation in a MAUI::Image widget, you can set up four frames for the animation in the .lst file.

.res ANIMATION
.image "frame1.png"
.res
.image "frame2.png"
.res
.image "frame3.png"
.res ENDANIMATION
.image "frame4.png"

Each image has its own .res declaration, which will create an index number for it, but it doesn’t need to be named. As MAHandle is a synonym for ‘int’, you can perform arithmetic operations on it. This excerpt will update an image every time a downloader informs your listener that more data has been downloaded, and you can update an animation on screen to show your user that it is working.

MAHandle h = ANIMATION;
Image* waitingAnim = new Image(0, 0, 100, 100, NULL);
...
void NotifyProgress(Downloader* dl, int downloadedBytes, int totalBytes)
{
    h = h++;
    if(h > ENDANIMATION)
    h = ANIMATION;
    waitingAnim->setResource(h);
}

When the listener’s notifyProgress method is called, the resource on the MAUI::Image widget is updated.

Loaded and Unloaded Resources

There are two variations on some of the examples we’ve seen. Normally, resource files are loaded into memory, and are read directly from there. With some files, this makes perfect sense. You should only include fonts you want to use, and it is going to need access to it. For other resources, such as media files (MP3) and program data, it may be wasteful to have all of them loaded into memory at the same time. You may have three MP3 files, but you can only play one at a time. To handle this more efficiently, you can mark these as being unloaded with either .ubin (for data files) and .umedia (for MP3 files). These will only then be loaded when required.

You can also load other resources on demand. For instance, you can offer the user a choice of skins or background images for the application. Normally, all these resources will be loaded when the application starts, but you can defer it until a time when it is needed. This will reduce the start up time and the memory consumption. Loading resources on demand is slower overall than loading at start up though. The benefits are that you’re not loading resources you won’t need, and that the loading time is spread.

There is no difference in how you use unloaded binary and media resources.

There is another way to work with unloaded resources which are not .ubin or .umedia. The directive .skip means that this resource will not be loaded when the application starts. This is particularly useful if you’ve got large resources which you may not need. They are not taking up loading time or precious memory if you’re not going to use them.

.res BGIMAGE2
.skip
.image "resources/background2.png"

Once you’ve created them, you can use them as you would any .image resource. There is no additional code required. They do take slightly longer to load than they would at application start up, but the user probably won’t even notice.

Strings and Localisation

One easy way to localise your application is to keep all the system text like buttons and labels held externally to your compiled application. The application can then read in the strings that it wants to use. You can create a different version of the resource file for each language.

Reading in strings from the resource file isn’t necessarily obvious however, and I’ve created a few example of how you can do it.

C++ Strings are very strange if you come from a Java or C# background. They are not as ubiquitous as they are in Java and C#, and are quite frankly, of limited use.

They are not inherent objects, and many method calls do not accept Strings but char* or const char* instead. This means that you are constantly converting between String and char*, which can be verbose and laborious.

The MoSync resource compiler handles strings in three different formats

.string

Does not include a null-terminator at the end of the string

.cstring

Does include the null-terminator

.pstring

A Pascal string, which puts a byte at the start of the string containing the length.

To read the value of the string, it isn’t as simple as

String* myString = new String(RESOURCENAME);

Instead, you have to make a more explicit call out to the resources file. There is an object which can help with this called DataHandler. This will let you read from the handle, and keeps track of its own position.

bool GetString(DataHandler* dh, String& output)
{
    char c;
    output.clear();
    if(!dh->read(&c, 1))
    {
        return false;
    }
    while(c) 
    {
        output.append(&c, 1);
        if(!dh->read(&c, 1)) 
        {
            return false;
        }
    }
    return true;
}

In the first example above, you can see that the method takes a DataHandler and a String as parameters. It uses the DataHandler to read from the resource file one character at a time, and builds the string. 

This on its own should be enough to convince you to always use .pstring whenever possible.

You can avoid a String object and create the string in a faster way using this function.

char* GetString(MAHandle stringResource)
{
    // Get the length of the string data.
    int length = maGetDataSize(stringResource);

    // Allocate space for the string data plus the
    // null termination character.
    char* buffer = new char[length + 1];

    // Read data.
    maReadData(stringResource, buffer, 0, length);

    // Null terminate the string.
    buffer[length] = 'TEMPLATE_PAGE_CONTENT';

    // Return the string.
    return buffer;
}

This returns a char* to your string, but it doesn’t delete it. You will need to call

delete[] buffer;

when you’ve finished with it. It uses the function maGetDataSize() to determine the length of the string and then reads it in one go. It will add the null terminator on, so this would be suitable with resource string of the .string type.

The next example read Pascal strings into a String object without doing it character by character:

bool GetPascalString(MAHandle stringResource, String& output)
{
    bool success = false;
    output.clear();
    DataHandler* dataHandler = new DataHandler(stringResource);
    byte length;
    if(dataHandler->read(&length, 1))
    {
        char* buffer = new char[length];
        dataHandler ->read(buffer, length);
        output.setData(new StringData<char>(buffer));
        delete[] buffer;
        success = true;
    }
    delete dataHandler ;
    return success;
}

It uses the DataHandler as well, and it creates a new StringData object with the string in. This would be a good way to read .pstrings from the resources file.

Finally, the fourth way doesn’t make use of DataHandler, and will probably be the fastest and sleekest way to read strings:

bool GetPascalStringWithoutDataHandler(MAHandle stringResource, String& output)
{
    output.clear();
    byte length;
    
    // Check that there is at least one byte.
    if(maGetDataSize(stringResource) == 0)
    return false;
    
    // Read byte size.
    maReadData(stringResource, &length, 0, 1);
    char* buffer = new char[length];
    maReadData(stringResource, buffer, 1, length);
    output.setData(new StringData(buffer));
    delete[] buffer;
    return true;
}

It uses the underlying maReadData() function, which is wrapped by DataHandler to read the string from the resource. It also creates a new StringData object, and it deletes its temporary char array.

Binary Data

You can create or load binary data to use in your application. This may be a proprietary data format, or it may be a way of creating screens dynamically using localised resource files. The directive .bin indicates that this should be included as raw binary data.

There are two ways to do this. Firstly, if you’ve already got some binary data you want to use

.res BINARYDEMO
.bin
.include "resources/data.bin"

This will include your data for you to process as you see fit.

A second way is for you to describe it in the resource file itself.

.res BINARYDEMO
.bin
.byte 4 //The number of widgets
.byte 1 //A label widget
.pstring "This is the first item. It is a label"
.byte 2 //A button widget
.pstring "This is the second item. It looks like a button"
.byte 1 //A label widget
.pstring "The next item is an image"
.byte 3 //An Image widget
.word 14422 //The size of the image
.include "resources/test.png"

I’ve created some content I want to put on to the screen, using some of the resource techniques we’ve already looked at. I can write a simple parser to create screen dynamically at runtime.

(Creating screens at runtime is the subject of the tutorial Creating New Screens.)

// Read the first byte. This determines the number of widgets
maReadData(BINARYDEMO, &length, 0, 1);
while(completed < length)
{
    // Read the next byte. This is the type of widget
    maReadData(BINARYDEMO, &widgetType, position, 1);
    position++;
    switch(widgetType)
    {
    case 1: // Label
        position += getPString(BINARYDEMO, *text, position);
        listbox->add(createLabel(text->c_str()));
        break;
    case 2: // Button
        position += getPString(BINARYDEMO, *text, position);
        listbox->add(createButton(text->c_str()));
        break;
    case 3: // Image
        lprintfln("Creating image");

        // Get the length of the image
        maReadData(BINARYDEMO, &imageLen, position, 4);
        position += 4;
        lprintfln("Image is %d bytes", imageLen);

        // Create a temporary placeholder
        MAHandle imagePlaceholder = maCreatePlaceholder();
    
        // Create an image from binary data
        maCreateImageFromData(imagePlaceholder, BINARYDEMO, position, imageLen);

        // Add the image to the listbox
        listbox->add(new Image(0, 0, 100, 100, NULL, true, true, imagePlaceholder));
        position += imageLen;
        lprintfln("Image created");
        break;
    }
    completed++;
}

This is an extract from the accompanying source code. It reads through the binary data we’ve put into the resource file, and creates the appropriate widgets at runtime. You can change the content of you application by just changing the resource file. You can share the resource file with clients and translators without giving away all of your code. This is the screen it produces:

MoSync SDK 3.3
Copyright © 2013 MoSync AB
www.mosync.com