js-ctypes: from C to JavaScript to C
Monday, October 13th, 2014Contact ‘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:
- Load the shared object
libexample2.so
- Declare a data type that matches the
struct st_t
- Declare a pointer to the previously defined JavaScript struct
- Declare functions that match with the c-functions listed above
- Operate the data received from the C library
- 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