Monday, December 19, 2011

How to use the raw resource files in the native code


Russian translation. Pending...


As you know the Android application is packed to the ".apk" container and all resources of the application are there. But what if you want to use a resource file inside the native code? Sure, you may move it to the external card and do with it all what you want. But it seems to be a slightly clumsy way. Really, I want to treat a raw resource file as it was an ordinary file stream. What we have at start: java code able to open and work with raw data files. Here is the sample code:
    
    AssetFileDescriptor descriptor = context.getResources().
        openRawResourceFd(R.raw.rawFile);
    FileDescriptor fd = desc.getFileDescriptor();
Let's look at the documentation:

Instances of the file descriptor class serve as an opaque handle to the underlying machine-specific structure representing an open file, an open socket, or another source or sink of bytes.
So it is what we are looking for. Moreover from the "AssetFileDescriptor" we can get the length of the file and its offset in the "apk" file.
    long offset = descriptor.getStartOffset();
    long lenth = descriptor.getLength();
And, at last, how to get the real native file descriptor:
    try {
        Field field = fd.getClass().getDeclaredField("descriptor");
        field.setAccessible(true);
        nativeDescriptor = (Integer) field.get(fd);
    } catch (NoSuchFieldException e1) {
    } catch (IllegalArgumentException e) {
    } catch (IllegalAccessException e) {
    }
Again, let's look at the documentation about "raw" files:

Arbitrary files to save in their raw form
So, they are saved as is - without compression and we can read them. Now we may go to the native part with following entry data:

1. The native file descriptor of the "apk" file.
2. The Offset of the "raw" file.
3. The length of the "raw" file.

The base idea is to map this part of the "apk" file into a memory and use the "fmemopen" function to get the "FILE" structure. Android doesn't support the "fmemopen" function, but you can find its implementation here:

fmemopen.c

And at last:
    int desc = dup(fd);
    long pa_offset = off & ~(sysconf(_SC_PAGE_SIZE) - 1);

    void *mapped = mmap(NULL, len + off - pa_offset, PROT_READ,
   MAP_PRIVATE, desc, pa_offset);
    if (mapped == MAP_FAILED) {
        ... error handling...
    }

    FILE *memoFile = fmemopen((void*) (mapped + off - pa_offset), len, "r");
    if (memoFile == NULL){
        ... error handling...
    }
And don't forget to free resources...

2 comments:

  1. y u use some links in lite black color ?
    please show your blogs link with white color that can be viewed by visitors
    because it is very help full blog.

    iphone application development

    ReplyDelete
  2. I apologize for the inconvenience caused to. :)
    And thank you for your comment. I'll change all links.

    ReplyDelete