js-ctypes: from C to JavaScript to C

Contact ‘mar10 [a] krutt [punto] org’

In this tutorial I will show how to manipulate C data types:
numbers, chars, structures, pointers and c-strings in JavaScript.

I am assuming the reader is familiar with the Firefox Add-on SDK, otherwise it’s time to read this tutorial and keep in mind the jsctypes api.

You can download all the code here. Please READ the README and LICENSE txt files before to use the code.

Requirements:

  • A working gcc compiler. I am using gcc 4.8.2
  • A text editor
  • Firefox. I am using Firefox 32.0.3
  • The Add-ons SDK installed. I am using Add-on SDK 1.17

Step 1: The C language: structs, pointers, c-strings, …

We define the following struct:

struct st_t
{
  void   *self;
  char   *str;
  size_t  buff_size;
  int     i;
  float   f;
  char    c;
};

The self pointer is just a pointer to the memory block that hosts the struct. We also have a pointer to char that will hold a c-string. The size of the memory block pointed to by str is stored in buff_size. Remember that in C language, size_t is a data type that is machine dependent. It doesn’t have the same size in a 32 bit machine than in a 64 bit computer.

Access functions

In order to use our previously defined struct, we declare the following functions:

struct st_t *f_st_rand();
void f_st_free( struct st_t *st );
int f_st_save( struct st_t *st);

*f_st_rand() just allocates memory for a struct st_t and initializes the struct.

*f_st_free( struct st_t *st ) releases the memory block pointed to by st and by st->str.

*f_st_save( struct st_t *st) stores in a file named output.txt the values of the struct.

You must compile a shared object and install the .so file in your system. Otherwise, Firefox will be unable to locate the library.
See this tutorial for more details.

In our setting, the created shared object is libexample2.so.

Step 2: js-ctypes

In our main.js file we need to do this:

  1. Load the shared object libexample2.so
  2. Declare a data type that matches the struct st_t
  3. Declare a pointer to the previously defined JavaScript struct
  4. Declare functions that match with the c-functions listed above
  5. Operate the data received from the C library
  6. Call the access functions from JavaScript code

1. Loading ‘libexample2.so’

Easy:

var libexample2 = ctypes.open("libexample2.so");

2. Declaring a struct in JavaScript

We call the function ctypes.StructType in order to define a new JavaScript struct. To define a pointer we use: ctypes.PointerType( ... ). The argument must be a ctype that matches the type declared in the struct.

The code snippet for this task is listed below.

/*
 *   struct st_t
 *   {
 *     void   *self;
 *     char   *str;
 *     size_t  buff_size;
 *     int     i;
 *     float   f;
 *     char    c;
 *   };
 */

var st_t = new ctypes.StructType("st_t",
                      [ { "self": ctypes.PointerType(ctypes.void_t) },
                        { "str": ctypes.PointerType(ctypes.char) },
                        { "buff_size": ctypes.size_t },
                        { "i": ctypes.int },
                        { "f": ctypes.float },
                        { "c": ctypes.char } ]);

3. Pointers to structs in JavaScript

Easy:

var st_ptr_t = ctypes.PointerType(st_t);

4. JavaSctipt functions

We need to use our previously defined variable libexample2 and the method declare:

var f_st_rand = libexample2.declare("f_st_rand",     /* function name  */
                              ctypes.default_abi,    /* call ABI       */
                              st_ptr_t);             /* return type    */

var f_st_free = libexample2.declare("f_st_free",     /* function name  */
                              ctypes.default_abi,    /* call ABI       */
                              ctypes.void_t,         /* return type    */
                              st_ptr_t);             /* fcn's argument */

var f_st_save = libexample2.declare("f_st_save",     /* function name  */
                              ctypes.default_abi,    /* call ABI       */
                              ctypes.int,            /* return type    */
                              st_ptr_t );            /* fcn's argument */

5. Modifying C variables in JavaScript

Primitive C-data-types are handled in a similar way that JavaScript types. However for pointers, c-strings and similar stuff we must act very carefully.

C-strings in JavaScript

We need to do a trick in JavaScript in order to use a memory block formatted for a c-string. The JavaScript pointer must be casted to another JS pointer with the same type but specific size. Memory blocks coming from C code don’t carry that information.

 var ptr = ctypes.cast( st.str, ctypes.ArrayType( ctypes.char, st.buff_size ).ptr );

We use an ctypes.char array of specific size (the same size of our buffer). The property ptr of this array is used to get a pointer.

Assigning a JavaScript string to a c-string

Easy:

ptr.contents = String("Hello world from JavaScript!!!");

6. Calling the c-functions from JavaScript

We just use our JavaScript functions:

var st_ptr = f_st_rand();
f_st_save( st_ptr ); 
f_st_free( st_ptr );

Final remarks

Once the code is ready we create the xpi file and we install it in Firefox via the Add-on manager.

It’s recommended that you open the Firefox Console during the execution of this add-on in order to catch any message coming from the add-on.

See also

License

Copyright (C) 2014 mar10

Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.3
or any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts.

A copy of the license can be found here

Tags: , , , ,

Comments are closed.