You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

191 lines
4.7 KiB

/*
* Examples of working with buffer objects from C code.
*/
/*
* Example 1: Buffer objects are created by Ecmascript code and then handed
* over to a Duktape/C function which accesses the raw bytes from C code.
*/
/*===
*** test_1 (duk_safe_call)
image size: 12x13, width_bytes: 2
...***......
...***......
...***......
..........*.
*****.**..*.
*****.***.*.
*****.*..***
.***.*....*.
..*.**......
...*.**.....
.**...**....
.**...**....
***...***...
final top: 0
==> rc=0, result='undefined'
===*/
static duk_ret_t draw_pixels(duk_context *ctx) {
unsigned char *ptr;
duk_size_t sz;
unsigned char *p;
long width, height;
long width_bytes;
long i, j;
/* Get data area of buffer argument (plain buffer or any
* duk_hbufferobject).
*
* The returned pointer is stable if the underlying buffer is a
* fixed buffer (this is always the case when a buffer object is
* created from Ecmascript code e.g. as "new ArrayBuffer()").
* For dynamic and external buffers the pointer is stable unless
* the buffer is resized or reconfigured. Caller is responsible
* for avoiding the use of stale pointers in such cases. When in
* doubt, relookup the pointer / length right before accessing.
*
* The duk_{get,require}_buffer_data() calls take into account
* "slices" so that the returned ptr/size is always to the active
* slice as one would expect compared to how buffers behave in
* Ecmascript code.
*/
ptr = duk_require_buffer_data(ctx, 0, &sz);
/* Get width and height. Buffer contains a 1-bit pixel image,
* with rows starting from top represented with ceil(width / 8)
* bytes.
*/
width = (long) duk_require_int(ctx, 1);
height = (long) duk_require_int(ctx, 2);
width_bytes = (width + 7) / 8;
printf("image size: %ldx%ld, width_bytes: %ld\n",
(long) width, (long) height, (long) width_bytes);
/* Caller must ensure it never accesses beyond the allowed buffer
* range which is [0, sz[. This is critical for memory safety.
*/
if (sz < width_bytes * height) {
return DUK_RET_RANGE_ERROR;
}
/* Print pixels. Actual user code could draw pixels to screen here. */
p = ptr - 1; /* dec by one, inner loop advances on first round */
for (i = 0; i < height; i++) {
for (j = 0; j < width; j++) {
unsigned char mask = 1 << (7 - (j & 0x07));
if ((j & 0x07) == 0) {
p++;
}
if (*p & mask) {
printf("*");
} else {
printf(".");
}
}
printf("\n");
}
return 0;
}
static duk_ret_t test_1(duk_context *ctx, void *udata) {
(void) udata;
duk_push_c_function(ctx, draw_pixels, 3 /*nargs*/);
duk_put_global_string(ctx, "drawPixels");
/*
...***.. ....
...***.. .... 13 rows
...***.. .... 12 pixels/row (2 bytes)
........ ..*.
*****.** ..*.
*****.** *.*.
*****.*. .***
.***.*.. ..*.
..*.**.. ....
...*.**. ....
.**...** ....
.**...** ....
***...** *...
*/
duk_eval_string_noresult(ctx,
"(function () {\n"
" var buf = new Buffer(13 * 2);\n"
" buf[0] = 0x1c; buf[1] = 0x00;\n"
" buf[2] = 0x1c; buf[3] = 0x00;\n"
" buf[4] = 0x1c; buf[5] = 0x00;\n"
" buf[6] = 0x00; buf[7] = 0x20;\n"
" buf[8] = 0xfb; buf[9] = 0x20;\n"
" buf[10] = 0xfb; buf[11] = 0xa0;\n"
" buf[12] = 0xfa; buf[13] = 0x70;\n"
" buf[14] = 0x74; buf[15] = 0x20;\n"
" buf[16] = 0x2c; buf[17] = 0x00;\n"
" buf[18] = 0x16; buf[19] = 0x00;\n"
" buf[20] = 0x63; buf[21] = 0x00;\n"
" buf[22] = 0x63; buf[23] = 0x00;\n"
" buf[24] = 0xe3; buf[25] = 0x80;\n"
" drawPixels(buf, 12 /*width*/, 13 /*height*/);\n"
"\n"
"})()\n"
);
printf("final top: %ld\n", (long) duk_get_top(ctx));
return 0;
}
/*
* Example 2: buffer object is created from C code and used in
* Ecmascript code.
*/
/*===
*** test_2 (duk_safe_call)
[object Uint32Array]
8
final top: 1
==> rc=0, result='undefined'
===*/
static duk_ret_t test_2(duk_context *ctx, void *udata) {
(void) udata;
duk_eval_string(ctx,
"(function test(buf) {\n"
" print(Object.prototype.toString.call(buf));\n"
" print(buf.length);\n"
" buf[0] = 0xdeadbeef;\n"
"})");
/* Create plain buffer which backs the buffer object. */
duk_push_fixed_buffer(ctx, 256);
/* Create a Uint32Array of 8 entries (32 bytes) mapping to
* the byte range [16,48[ of the underlying buffer.
*/
duk_push_buffer_object(ctx, -1, 16, 32, DUK_BUFOBJ_UINT32ARRAY); /* offset 16, length 32 bytes, Uint32Array of 8 entries */
/* The plain buffer is now referenced by the buffer object
* and doesn't need to be kept explicitly reachable.
*/
duk_remove(ctx, -2);
/* [ func bufferobject ] */
duk_call(ctx, 1);
printf("final top: %ld\n", (long) duk_get_top(ctx));
return 0;
}
/*
* Main
*/
void test(duk_context *ctx) {
TEST_SAFE_CALL(test_1);
TEST_SAFE_CALL(test_2);
}