1
0
mirror of https://github.com/Ylianst/MeshAgent synced 2025-12-22 19:23:31 +00:00
Files
MeshAgent/microscript/ILibDuktape_Polyfills.c
2018-01-12 11:50:04 -08:00

969 lines
32 KiB
C

#include "duktape.h"
#include "ILibDuktape_Helpers.h"
#include "ILibDuktapeModSearch.h"
#include "ILibDuktape_DuplexStream.h"
#include "ILibDuktape_EventEmitter.h"
#include "../microstack/ILibParsers.h"
#include "../microstack/ILibCrypto.h"
#define ILibDuktape_Timer_Ptrs "\xFF_DuktapeTimer_PTRS"
#define ILibDuktape_Queue_Ptr "\xFF_Queue"
duk_ret_t ILibDuktape_Pollyfills_Buffer_slice(duk_context *ctx)
{
int nargs = duk_get_top(ctx);
char *buffer;
char *out;
duk_size_t bufferLen;
int offset = 0;
duk_push_this(ctx);
buffer = Duktape_GetBuffer(ctx, -1, &bufferLen);
if (nargs >= 1)
{
offset = duk_require_int(ctx, 0);
bufferLen -= offset;
}
if (nargs == 2)
{
bufferLen = (duk_size_t)duk_require_int(ctx, 1) - offset;
}
duk_push_fixed_buffer(ctx, bufferLen);
out = Duktape_GetBuffer(ctx, -1, NULL);
memcpy_s(out, bufferLen, buffer + offset, bufferLen);
return 1;
}
duk_ret_t ILibDuktape_Polyfills_Buffer_toString(duk_context *ctx)
{
int nargs = duk_get_top(ctx);
char *buffer, *tmpBuffer;
duk_size_t bufferLen;
char *cType;
duk_push_this(ctx); // [buffer]
buffer = Duktape_GetBuffer(ctx, -1, &bufferLen);
if (nargs == 0)
{
// Just convert to a string
duk_push_lstring(ctx, buffer, bufferLen); // [buffer][string]
}
else
{
cType = (char*)duk_require_string(ctx, 0);
if (strcmp(cType, "base64") == 0)
{
duk_push_fixed_buffer(ctx, ILibBase64EncodeLength((int)bufferLen));
tmpBuffer = Duktape_GetBuffer(ctx, -1, NULL);
ILibBase64Encode((unsigned char*)buffer, (int)bufferLen, (unsigned char**)&tmpBuffer);
duk_push_string(ctx, tmpBuffer);
}
else if (strcmp(cType, "hex") == 0)
{
duk_push_fixed_buffer(ctx, 1 + (bufferLen * 2));
tmpBuffer = Duktape_GetBuffer(ctx, -1, NULL);
util_tohex(buffer, (int)bufferLen, tmpBuffer);
duk_push_string(ctx, tmpBuffer);
}
else if (strcmp(cType, "hex:") == 0)
{
duk_push_fixed_buffer(ctx, 1 + (bufferLen * 3));
tmpBuffer = Duktape_GetBuffer(ctx, -1, NULL);
util_tohex2(buffer, (int)bufferLen, tmpBuffer);
duk_push_string(ctx, tmpBuffer);
}
else
{
duk_push_string(ctx, "buffer.toString(): Unrecognized parameter");
duk_throw(ctx);
return(DUK_RET_ERROR);
}
}
return 1;
}
duk_ret_t ILibDuktape_Polyfills_Buffer_from(duk_context *ctx)
{
int nargs = duk_get_top(ctx);
char *str;
duk_size_t strlength;
char *encoding;
char *buffer;
int bufferLen;
if (nargs == 1)
{
str = (char*)duk_get_lstring(ctx, 0, &strlength);
duk_push_fixed_buffer(ctx, strlength);
buffer = Duktape_GetBuffer(ctx, -1, NULL);
memcpy_s(buffer, strlength, str, strlength);
duk_push_buffer_object(ctx, -1, 0, strlength, DUK_BUFOBJ_NODEJS_BUFFER);
return(1);
}
else if(!(nargs == 2 && duk_is_string(ctx, 0) && duk_is_string(ctx, 1)))
{
duk_push_string(ctx, "Buffer.from(): Usage not supported yet.");
duk_throw(ctx);
return(DUK_RET_ERROR);
}
str = (char*)duk_get_lstring(ctx, 0, &strlength);
encoding = (char*)duk_require_string(ctx, 1);
if (strcmp(encoding, "base64") == 0)
{
// Base64
duk_push_fixed_buffer(ctx, ILibBase64DecodeLength((int)strlength));
buffer = Duktape_GetBuffer(ctx, -1, NULL);
bufferLen = ILibBase64Decode((unsigned char*)str, (int)strlength, (unsigned char**)&buffer);
duk_push_buffer_object(ctx, -1, 0, bufferLen, DUK_BUFOBJ_NODEJS_BUFFER);
}
else if (strcmp(encoding, "hex") == 0)
{
duk_push_fixed_buffer(ctx, strlength / 2);
buffer = Duktape_GetBuffer(ctx, -1, NULL);
bufferLen = util_hexToBuf(str, (int)strlength, buffer);
duk_push_buffer_object(ctx, -1, 0, bufferLen, DUK_BUFOBJ_NODEJS_BUFFER);
}
else
{
duk_push_string(ctx, "Buffer.from(): Encoding not supported yet.");
duk_throw(ctx);
return(DUK_RET_ERROR);
}
return 1;
}
duk_ret_t ILibDuktape_Polyfills_Buffer_readInt32BE(duk_context *ctx)
{
int offset = duk_require_int(ctx, 0);
char *buffer;
duk_size_t bufferLen;
duk_push_this(ctx);
buffer = Duktape_GetBuffer(ctx, -1, &bufferLen);
duk_push_int(ctx, ntohl(((int*)(buffer + offset))[0]));
return(1);
}
duk_ret_t ILibDuktape_Polyfills_Buffer_alloc(duk_context *ctx)
{
int sz = duk_require_int(ctx, 0);
duk_push_fixed_buffer(ctx, sz);
char *buffer = Duktape_GetBuffer(ctx, -1, NULL);
memset(buffer, 0, sz);
duk_push_buffer_object(ctx, -1, 0, sz, DUK_BUFOBJ_NODEJS_BUFFER);
return(1);
}
void ILibDuktape_Polyfills_Buffer(duk_context *ctx)
{
// Polyfill 'Buffer.slice'
duk_get_prop_string(ctx, -1, "Duktape"); // [g][Duktape]
duk_get_prop_string(ctx, -1, "Buffer"); // [g][Duktape][Buffer]
duk_get_prop_string(ctx, -1, "prototype"); // [g][Duktape][Buffer][prototype]
duk_push_c_function(ctx, ILibDuktape_Pollyfills_Buffer_slice, DUK_VARARGS); // [g][Duktape][Buffer][prototype][func]
duk_put_prop_string(ctx, -2, "slice"); // [g][Duktape][Buffer][prototype]
duk_push_c_function(ctx, ILibDuktape_Polyfills_Buffer_readInt32BE, DUK_VARARGS);// [g][Duktape][Buffer][prototype][func]
duk_put_prop_string(ctx, -2, "readInt32BE"); // [g][Duktape][Buffer][prototype]
duk_pop_3(ctx); // [g]
// Polyfill 'Buffer.toString()
duk_get_prop_string(ctx, -1, "Duktape"); // [g][Duktape]
duk_get_prop_string(ctx, -1, "Buffer"); // [g][Duktape][Buffer]
duk_get_prop_string(ctx, -1, "prototype"); // [g][Duktape][Buffer][prototype]
duk_push_c_function(ctx, ILibDuktape_Polyfills_Buffer_toString, DUK_VARARGS); // [g][Duktape][Buffer][prototype][func]
duk_put_prop_string(ctx, -2, "toString"); // [g][Duktape][Buffer][prototype]
duk_pop_3(ctx); // [g]
// Polyfill Buffer.from()
duk_get_prop_string(ctx, -1, "Buffer"); // [g][Buffer]
duk_push_c_function(ctx, ILibDuktape_Polyfills_Buffer_from, DUK_VARARGS); // [g][Buffer][func]
duk_put_prop_string(ctx, -2, "from"); // [g][Buffer]
duk_pop(ctx); // [g]
// Polyfill Buffer.alloc() for Node Buffers)
duk_get_prop_string(ctx, -1, "Buffer"); // [g][Buffer]
duk_push_c_function(ctx, ILibDuktape_Polyfills_Buffer_alloc, DUK_VARARGS); // [g][Buffer][func]
duk_put_prop_string(ctx, -2, "alloc"); // [g][Buffer]
duk_pop(ctx); // [g]
// Polyfill Buffer.toString() for Node Buffers
duk_get_prop_string(ctx, -1, "Buffer"); // [g][Buffer]
duk_get_prop_string(ctx, -1, "prototype"); // [g][Buffer][prototype]
duk_push_c_function(ctx, ILibDuktape_Polyfills_Buffer_toString, DUK_VARARGS); // [g][Buffer][prototype][func]
duk_put_prop_string(ctx, -2, "toString"); // [g][Buffer][prototype]
duk_pop_2(ctx); // [g]
}
duk_ret_t ILibDuktape_Polyfills_String_startsWith(duk_context *ctx)
{
duk_size_t tokenLen;
char *token = Duktape_GetBuffer(ctx, 0, &tokenLen);
char *buffer;
duk_size_t bufferLen;
duk_push_this(ctx);
buffer = Duktape_GetBuffer(ctx, -1, &bufferLen);
if (ILibString_StartsWith(buffer, (int)bufferLen, token, (int)tokenLen) != 0)
{
duk_push_true(ctx);
}
else
{
duk_push_false(ctx);
}
return 1;
}
duk_ret_t ILibDuktape_Polyfills_String_endsWith(duk_context *ctx)
{
duk_size_t tokenLen;
char *token = Duktape_GetBuffer(ctx, 0, &tokenLen);
char *buffer;
duk_size_t bufferLen;
duk_push_this(ctx);
buffer = Duktape_GetBuffer(ctx, -1, &bufferLen);
if (ILibString_EndsWith(buffer, (int)bufferLen, token, (int)tokenLen) != 0)
{
duk_push_true(ctx);
}
else
{
duk_push_false(ctx);
}
return 1;
}
void ILibDuktape_Polyfills_String(duk_context *ctx)
{
// Polyfill 'String.startsWith'
duk_get_prop_string(ctx, -1, "String"); // [string]
duk_get_prop_string(ctx, -1, "prototype"); // [string][proto]
duk_push_c_function(ctx, ILibDuktape_Polyfills_String_startsWith, DUK_VARARGS); // [string][proto][func]
duk_put_prop_string(ctx, -2, "startsWith"); // [string][proto]
duk_push_c_function(ctx, ILibDuktape_Polyfills_String_endsWith, DUK_VARARGS); // [string][proto][func]
duk_put_prop_string(ctx, -2, "endsWith"); // [string][proto]
duk_pop_2(ctx);
}
duk_ret_t ILibDuktape_Polyfills_Console_log(duk_context *ctx)
{
int numargs = duk_get_top(ctx);
int i;
for (i = 0; i < numargs; ++i)
{
if (duk_is_string(ctx, i))
{
printf("%s%s", (i == 0 ? "" : ", "), duk_require_string(ctx, i));
}
else
{
duk_dup(ctx, i);
if (strcmp("[object Object]", duk_to_string(ctx, -1)) == 0)
{
duk_pop(ctx);
duk_dup(ctx, i);
printf("%s", (i == 0 ? "{" : ", {"));
duk_enum(ctx, -1, DUK_ENUM_OWN_PROPERTIES_ONLY);
int propNum = 0;
while (duk_next(ctx, -1, 1))
{
printf("%s%s: %s", ((propNum++ == 0) ? " " : ", "), (char*)duk_to_string(ctx, -2), (char*)duk_to_string(ctx, -1));
duk_pop_2(ctx);
}
duk_pop(ctx);
printf(" }");
}
else
{
printf("%s%s", (i == 0 ? "" : ", "), duk_to_string(ctx, -1));
}
}
}
printf("\n");
return 0;
}
duk_ret_t ILibDuktape_Polyfills_Console_enableWebLog(duk_context *ctx)
{
#ifdef _REMOTELOGGING
void *chain = Duktape_GetChain(ctx);
int port = duk_require_int(ctx, 0);
duk_size_t pLen;
if (duk_peval_string(ctx, "process.argv0") != 0) { return(ILibDuktape_Error(ctx, "console.enableWebLog(): Couldn't fetch argv0")); }
char *p = (char*)duk_get_lstring(ctx, -1, &pLen);
if (ILibString_EndsWith(p, (int)pLen, ".js", 3) != 0)
{
memcpy_s(ILibScratchPad2, sizeof(ILibScratchPad2), p, pLen - 3);
sprintf_s(ILibScratchPad2 + (pLen - 3), sizeof(ILibScratchPad2) - 3, ".wlg");
}
else if (ILibString_EndsWith(p, (int)pLen, ".exe", 3) != 0)
{
memcpy_s(ILibScratchPad2, sizeof(ILibScratchPad2), p, pLen - 4);
sprintf_s(ILibScratchPad2 + (pLen - 3), sizeof(ILibScratchPad2) - 4, ".wlg");
}
else
{
sprintf_s(ILibScratchPad2, sizeof(ILibScratchPad2), "%s.wlg", p);
}
ILibStartDefaultLoggerEx(chain, (unsigned short)port, ILibScratchPad2);
#endif
return (0);
}
void ILibDuktape_Polyfills_Console(duk_context *ctx)
{
// Polyfill console.log()
if (duk_has_prop_string(ctx, -1, "console"))
{
duk_get_prop_string(ctx, -1, "console"); // [g][console]
}
else
{
duk_push_object(ctx); // [g][console]
duk_dup(ctx, -1); // [g][console][console]
duk_put_prop_string(ctx, -3, "console"); // [g][console]
}
duk_push_c_function(ctx, ILibDuktape_Polyfills_Console_log, DUK_VARARGS); // [g][console][log]
duk_put_prop_string(ctx, -2, "log"); // [g][console]
ILibDuktape_CreateInstanceMethod(ctx, "enableWebLog", ILibDuktape_Polyfills_Console_enableWebLog, 1);
duk_pop(ctx); // [g]
}
duk_ret_t ILibDuktape_ntohl(duk_context *ctx)
{
duk_size_t bufferLen;
char *buffer = Duktape_GetBuffer(ctx, 0, &bufferLen);
int offset = duk_require_int(ctx, 1);
if ((int)bufferLen < (4 + offset)) { duk_push_string(ctx, "buffer too small"); duk_throw(ctx); return(DUK_RET_ERROR); }
duk_push_int(ctx, ntohl(((unsigned int*)(buffer + offset))[0]));
return 1;
}
duk_ret_t ILibDuktape_ntohs(duk_context *ctx)
{
duk_size_t bufferLen;
char *buffer = Duktape_GetBuffer(ctx, 0, &bufferLen);
int offset = duk_require_int(ctx, 1);
if ((int)bufferLen < 2 + offset) { duk_push_string(ctx, "buffer too small"); duk_throw(ctx); return(DUK_RET_ERROR); }
duk_push_int(ctx, ntohs(((unsigned short*)(buffer + offset))[0]));
return 1;
}
duk_ret_t ILibDuktape_htonl(duk_context *ctx)
{
duk_size_t bufferLen;
char *buffer = Duktape_GetBuffer(ctx, 0, &bufferLen);
int offset = duk_require_int(ctx, 1);
unsigned int val = (unsigned int)duk_require_int(ctx, 2);
if ((int)bufferLen < (4 + offset)) { duk_push_string(ctx, "buffer too small"); duk_throw(ctx); return(DUK_RET_ERROR); }
((unsigned int*)(buffer + offset))[0] = htonl(val);
return 0;
}
duk_ret_t ILibDuktape_htons(duk_context *ctx)
{
duk_size_t bufferLen;
char *buffer = Duktape_GetBuffer(ctx, 0, &bufferLen);
int offset = duk_require_int(ctx, 1);
unsigned int val = (unsigned int)duk_require_int(ctx, 2);
if ((int)bufferLen < (2 + offset)) { duk_push_string(ctx, "buffer too small"); duk_throw(ctx); return(DUK_RET_ERROR); }
((unsigned short*)(buffer + offset))[0] = htons(val);
return 0;
}
void ILibDuktape_Polyfills_byte_ordering(duk_context *ctx)
{
ILibDuktape_CreateInstanceMethod(ctx, "ntohl", ILibDuktape_ntohl, 2);
ILibDuktape_CreateInstanceMethod(ctx, "ntohs", ILibDuktape_ntohs, 2);
ILibDuktape_CreateInstanceMethod(ctx, "htonl", ILibDuktape_htonl, 3);
ILibDuktape_CreateInstanceMethod(ctx, "htons", ILibDuktape_htons, 3);
}
typedef enum ILibDuktape_Timer_Type
{
ILibDuktape_Timer_Type_TIMEOUT = 0,
ILibDuktape_Timer_Type_INTERVAL = 1,
ILibDuktape_Timer_Type_IMMEDIATE = 2
}ILibDuktape_Timer_Type;
typedef struct ILibDuktape_Timer
{
duk_context *ctx;
void *object;
void *callback;
void *args;
int timeout;
ILibDuktape_Timer_Type timerType;
}ILibDuktape_Timer;
duk_ret_t ILibDuktape_Polyfills_timer_finalizer(duk_context *ctx)
{
// Make sure we remove any timers just in case, so we don't leak resources
ILibDuktape_Timer *ptrs;
duk_get_prop_string(ctx, 0, ILibDuktape_Timer_Ptrs);
ptrs = (ILibDuktape_Timer*)Duktape_GetBuffer(ctx, -1, NULL);
ILibLifeTime_Remove(ILibGetBaseTimer(Duktape_GetChain(ctx)), ptrs);
return 0;
}
void ILibDuktape_Polyfills_timer_elapsed(void *obj)
{
ILibDuktape_Timer *ptrs = (ILibDuktape_Timer*)obj;
int argCount, i;
duk_context *ctx = ptrs->ctx;
if (ptrs->timerType == ILibDuktape_Timer_Type_INTERVAL)
{
ILibLifeTime_AddEx(ILibGetBaseTimer(Duktape_GetChain(ptrs->ctx)), ptrs, ptrs->timeout, ILibDuktape_Polyfills_timer_elapsed, NULL);
}
duk_push_heapptr(ptrs->ctx, ptrs->callback); // [func]
duk_push_heapptr(ptrs->ctx, ptrs->object); // [func][this]
duk_push_heapptr(ptrs->ctx, ptrs->args); // [func][this][argArray]
argCount = (int)duk_get_length(ptrs->ctx, -1);
for (i = 0; i < argCount; ++i)
{
duk_get_prop_index(ptrs->ctx, -1, i); // [func][this][argArray][arg]
duk_swap_top(ptrs->ctx, -2); // [func][this][arg][argArray]
}
duk_pop(ptrs->ctx); // [func][this][...arg...]
if (duk_pcall_method(ptrs->ctx, argCount) != 0) { ILibDuktape_Process_UncaughtExceptionEx(ptrs->ctx, "timers.onElapsed() callback handler"); }
duk_pop(ctx); // ...
}
duk_ret_t ILibDuktape_Polyfills_timer_set(duk_context *ctx)
{
int nargs = duk_get_top(ctx);
ILibDuktape_Timer *ptrs;
ILibDuktape_Timer_Type timerType;
void *chain = Duktape_GetChain(ctx);
int argx;
duk_push_current_function(ctx);
duk_get_prop_string(ctx, -1, "type");
timerType = (ILibDuktape_Timer_Type)duk_get_int(ctx, -1);
duk_push_object(ctx); //[retVal]
ILibDuktape_CreateFinalizer(ctx, ILibDuktape_Polyfills_timer_finalizer);
duk_push_fixed_buffer(ctx, sizeof(ILibDuktape_Timer)); //[retVal][ptrs]
ptrs = (ILibDuktape_Timer*)Duktape_GetBuffer(ctx, -1, NULL);
memset(ptrs, 0, sizeof(ILibDuktape_Timer));
duk_put_prop_string(ctx, -2, ILibDuktape_Timer_Ptrs); //[retVal]
ptrs->ctx = ctx;
ptrs->object = duk_get_heapptr(ctx, -1);
ptrs->timerType = timerType;
ptrs->timeout = timerType == ILibDuktape_Timer_Type_IMMEDIATE ? 0 : (int)duk_require_int(ctx, 1);
ptrs->callback = duk_require_heapptr(ctx, 0);
duk_push_array(ctx); //[retVal][argArray]
for (argx = ILibDuktape_Timer_Type_IMMEDIATE == timerType ? 1 : 2; argx < nargs; ++argx)
{
duk_dup(ctx, argx); //[retVal][argArray][arg]
duk_put_prop_index(ctx, -2, argx - (ILibDuktape_Timer_Type_IMMEDIATE == timerType ? 1 : 2)); //[retVal][argArray]
}
ptrs->args = duk_get_heapptr(ctx, -1);
duk_put_prop_string(ctx, -2, "\xFF_argArray");
duk_dup(ctx, 0); //[retVal][callback]
duk_put_prop_string(ctx, -2, "\xFF_callback"); //[retVal]
ILibLifeTime_AddEx(ILibGetBaseTimer(chain), ptrs, ptrs->timeout, ILibDuktape_Polyfills_timer_elapsed, NULL);
return 1;
}
duk_ret_t ILibDuktape_Polyfills_timer_clear(duk_context *ctx)
{
ILibDuktape_Timer *ptrs;
ILibDuktape_Timer_Type timerType;
duk_push_current_function(ctx);
duk_get_prop_string(ctx, -1, "type");
timerType = (ILibDuktape_Timer_Type)duk_get_int(ctx, -1);
if(!duk_has_prop_string(ctx, 0, ILibDuktape_Timer_Ptrs))
{
switch (timerType)
{
case ILibDuktape_Timer_Type_TIMEOUT:
return(ILibDuktape_Error(ctx, "timers.clearTimeout(): Invalid Parameter"));
case ILibDuktape_Timer_Type_INTERVAL:
return(ILibDuktape_Error(ctx, "timers.clearInterval(): Invalid Parameter"));
case ILibDuktape_Timer_Type_IMMEDIATE:
return(ILibDuktape_Error(ctx, "timers.clearImmediate(): Invalid Parameter"));
}
}
duk_get_prop_string(ctx, 0, ILibDuktape_Timer_Ptrs);
ptrs = (ILibDuktape_Timer*)Duktape_GetBuffer(ctx, -1, NULL);
ILibLifeTime_Remove(ILibGetBaseTimer(Duktape_GetChain(ctx)), ptrs);
return 0;
}
void ILibDuktape_Polyfills_timer(duk_context *ctx)
{
ILibDuktape_CreateInstanceMethodWithIntProperty(ctx, "type", ILibDuktape_Timer_Type_TIMEOUT, "setTimeout", ILibDuktape_Polyfills_timer_set, DUK_VARARGS);
ILibDuktape_CreateInstanceMethodWithIntProperty(ctx, "type", ILibDuktape_Timer_Type_INTERVAL, "setInterval", ILibDuktape_Polyfills_timer_set, DUK_VARARGS);
ILibDuktape_CreateInstanceMethodWithIntProperty(ctx, "type", ILibDuktape_Timer_Type_IMMEDIATE, "setImmediate", ILibDuktape_Polyfills_timer_set, DUK_VARARGS);
ILibDuktape_CreateInstanceMethodWithIntProperty(ctx, "type", ILibDuktape_Timer_Type_TIMEOUT, "clearTimeout", ILibDuktape_Polyfills_timer_clear, 1);
ILibDuktape_CreateInstanceMethodWithIntProperty(ctx, "type", ILibDuktape_Timer_Type_INTERVAL, "clearInterval", ILibDuktape_Polyfills_timer_clear, 1);
ILibDuktape_CreateInstanceMethodWithIntProperty(ctx, "type", ILibDuktape_Timer_Type_IMMEDIATE, "clearImmediate", ILibDuktape_Polyfills_timer_clear, 1);
}
duk_ret_t ILibDuktape_Polyfills_addModule(duk_context *ctx)
{
duk_size_t moduleLen;
char *module = (char*)Duktape_GetBuffer(ctx, 1, &moduleLen);
char *moduleName = (char*)duk_require_string(ctx, 0);
if (ILibDuktape_ModSearch_AddModule(ctx, moduleName, module, (int)moduleLen) != 0)
{
return(ILibDuktape_Error(ctx, "Cannot add module: %s", moduleName));
}
return(0);
}
duk_ret_t ILibDuktape_Queue_Finalizer(duk_context *ctx)
{
duk_get_prop_string(ctx, 0, ILibDuktape_Queue_Ptr);
ILibQueue_Destroy((ILibQueue)duk_get_pointer(ctx, -1));
return(0);
}
duk_ret_t ILibDuktape_Queue_EnQueue(duk_context *ctx)
{
ILibQueue Q;
int i;
int nargs = duk_get_top(ctx);
duk_push_this(ctx); // [queue]
duk_get_prop_string(ctx, -1, ILibDuktape_Queue_Ptr); // [queue][ptr]
Q = (ILibQueue)duk_get_pointer(ctx, -1);
duk_pop(ctx); // [queue]
ILibDuktape_Push_ObjectStash(ctx); // [queue][stash]
duk_push_array(ctx); // [queue][stash][array]
for (i = 0; i < nargs; ++i)
{
duk_dup(ctx, i); // [queue][stash][array][arg]
duk_put_prop_index(ctx, -2, i); // [queue][stash][array]
}
ILibQueue_EnQueue(Q, duk_get_heapptr(ctx, -1));
duk_put_prop_string(ctx, -2, Duktape_GetStashKey(duk_get_heapptr(ctx, -1))); // [queue][stash]
return(0);
}
duk_ret_t ILibDuktape_Queue_DeQueue(duk_context *ctx)
{
duk_push_current_function(ctx);
duk_get_prop_string(ctx, -1, "peek");
int peek = duk_get_int(ctx, -1);
duk_push_this(ctx); // [Q]
duk_get_prop_string(ctx, -1, ILibDuktape_Queue_Ptr); // [Q][ptr]
ILibQueue Q = (ILibQueue)duk_get_pointer(ctx, -1);
void *h = peek == 0 ? ILibQueue_DeQueue(Q) : ILibQueue_PeekQueue(Q);
if (h == NULL) { return(ILibDuktape_Error(ctx, "Queue is empty")); }
duk_pop(ctx); // [Q]
ILibDuktape_Push_ObjectStash(ctx); // [Q][stash]
duk_push_heapptr(ctx, h); // [Q][stash][array]
int length = (int)duk_get_length(ctx, -1);
int i;
for (i = 0; i < length; ++i)
{
duk_get_prop_index(ctx, -i - 1, i); // [Q][stash][array][args]
}
if (peek == 0) { duk_del_prop_string(ctx, -length - 2, Duktape_GetStashKey(h)); }
return(length);
}
duk_ret_t ILibDuktape_Queue_new(duk_context *ctx)
{
duk_push_object(ctx); // [queue]
duk_push_pointer(ctx, ILibQueue_Create()); // [queue][ptr]
duk_put_prop_string(ctx, -2, ILibDuktape_Queue_Ptr); // [queue]
ILibDuktape_CreateFinalizer(ctx, ILibDuktape_Queue_Finalizer);
ILibDuktape_CreateInstanceMethod(ctx, "enQueue", ILibDuktape_Queue_EnQueue, DUK_VARARGS);
ILibDuktape_CreateInstanceMethodWithIntProperty(ctx, "peek", 0, "deQueue", ILibDuktape_Queue_DeQueue, DUK_VARARGS);
ILibDuktape_CreateInstanceMethodWithIntProperty(ctx, "peek", 1, "peekQueue", ILibDuktape_Queue_DeQueue, DUK_VARARGS);
return(1);
}
void ILibDuktape_Queue_Push(duk_context *ctx, void* chain)
{
duk_push_c_function(ctx, ILibDuktape_Queue_new, 0);
}
typedef struct ILibDuktape_DynamicBuffer_data
{
int start;
int end;
int unshiftBytes;
char *buffer;
int bufferLen;
}ILibDuktape_DynamicBuffer_data;
typedef struct ILibDuktape_DynamicBuffer_ContextSwitchData
{
void *chain;
void *heapptr;
ILibDuktape_DuplexStream *stream;
ILibDuktape_DynamicBuffer_data *data;
int bufferLen;
char buffer[];
}ILibDuktape_DynamicBuffer_ContextSwitchData;
ILibTransport_DoneState ILibDuktape_DynamicBuffer_WriteSink(ILibDuktape_DuplexStream *stream, char *buffer, int bufferLen, void *user);
void ILibDuktape_DynamicBuffer_WriteSink_ChainThread(void *chain, void *user)
{
ILibDuktape_DynamicBuffer_ContextSwitchData *data = (ILibDuktape_DynamicBuffer_ContextSwitchData*)user;
if (ILibDuktape_IsPointerValid(chain, data->heapptr) != 0)
{
ILibDuktape_DynamicBuffer_WriteSink(data->stream, data->buffer, data->bufferLen, data->data);
ILibDuktape_DuplexStream_Ready(data->stream);
}
free(user);
}
ILibTransport_DoneState ILibDuktape_DynamicBuffer_WriteSink(ILibDuktape_DuplexStream *stream, char *buffer, int bufferLen, void *user)
{
ILibDuktape_DynamicBuffer_data *data = (ILibDuktape_DynamicBuffer_data*)user;
if (ILibIsRunningOnChainThread(stream->readableStream->chain) == 0)
{
ILibDuktape_DynamicBuffer_ContextSwitchData *tmp = (ILibDuktape_DynamicBuffer_ContextSwitchData*)ILibMemory_Allocate(sizeof(ILibDuktape_DynamicBuffer_ContextSwitchData) + bufferLen, 0, NULL, NULL);
tmp->chain = stream->readableStream->chain;
tmp->heapptr = stream->ParentObject;
tmp->stream = stream;
tmp->data = data;
tmp->bufferLen = bufferLen;
memcpy_s(tmp->buffer, bufferLen, buffer, bufferLen);
ILibChain_RunOnMicrostackThread(tmp->chain, ILibDuktape_DynamicBuffer_WriteSink_ChainThread, tmp);
return(ILibTransport_DoneState_INCOMPLETE);
}
if ((data->bufferLen - data->start - data->end) < bufferLen)
{
if (data->end > 0)
{
// Move the buffer first
memmove_s(data->buffer, data->bufferLen, data->buffer + data->start, data->end);
data->start = 0;
}
if ((data->bufferLen - data->end) < bufferLen)
{
// Need to resize buffer first
int tmpSize = data->bufferLen;
while ((tmpSize - data->end) < bufferLen)
{
tmpSize += 4096;
}
data->buffer = (char*)realloc(data->buffer, tmpSize);
data->bufferLen = tmpSize;
}
}
memcpy_s(data->buffer + data->start + data->end, data->bufferLen - data->start - data->end, buffer, bufferLen);
data->end += bufferLen;
int unshifted = 0;
do
{
duk_push_heapptr(stream->readableStream->ctx, stream->ParentObject); // [ds]
duk_get_prop_string(stream->readableStream->ctx, -1, "emit"); // [ds][emit]
duk_swap_top(stream->readableStream->ctx, -2); // [emit][this]
duk_push_string(stream->readableStream->ctx, "readable"); // [emit][this][readable]
if (duk_pcall_method(stream->readableStream->ctx, 1) != 0) { ILibDuktape_Process_UncaughtExceptionEx(stream->readableStream->ctx, "DynamicBuffer.WriteSink => readable(): "); }
duk_pop(stream->readableStream->ctx); // ...
ILibDuktape_DuplexStream_WriteData(stream, data->buffer + data->start, data->end);
if (data->unshiftBytes == 0)
{
// All the data was consumed
data->start = data->end = 0;
}
else
{
unshifted = (data->end - data->unshiftBytes);
if (unshifted > 0)
{
data->start += unshifted;
data->end = data->unshiftBytes;
data->unshiftBytes = 0;
}
}
} while (unshifted != 0);
return(ILibTransport_DoneState_COMPLETE);
}
void ILibDuktape_DynamicBuffer_EndSink(ILibDuktape_DuplexStream *stream, void *user)
{
ILibDuktape_DuplexStream_WriteEnd(stream);
}
duk_ret_t ILibDuktape_DynamicBuffer_Finalizer(duk_context *ctx)
{
ILibDuktape_InValidateHeapPointer(ctx, 0);
duk_get_prop_string(ctx, 0, "\xFF_buffer");
ILibDuktape_DynamicBuffer_data *data = (ILibDuktape_DynamicBuffer_data*)Duktape_GetBuffer(ctx, -1, NULL);
free(data->buffer);
return(0);
}
int ILibDuktape_DynamicBuffer_unshift(ILibDuktape_DuplexStream *sender, int unshiftBytes, void *user)
{
ILibDuktape_DynamicBuffer_data *data = (ILibDuktape_DynamicBuffer_data*)user;
data->unshiftBytes = unshiftBytes;
return(unshiftBytes);
}
duk_ret_t ILibDuktape_DynamicBuffer_read(duk_context *ctx)
{
ILibDuktape_DynamicBuffer_data *data;
duk_push_this(ctx); // [DynamicBuffer]
duk_get_prop_string(ctx, -1, "\xFF_buffer"); // [DynamicBuffer][buffer]
data = (ILibDuktape_DynamicBuffer_data*)Duktape_GetBuffer(ctx, -1, NULL);
duk_push_external_buffer(ctx); // [DynamicBuffer][buffer][extBuffer]
duk_config_buffer(ctx, -1, data->buffer + data->start, data->bufferLen - (data->start + data->end));
duk_push_buffer_object(ctx, -1, 0, data->bufferLen - (data->start + data->end), DUK_BUFOBJ_NODEJS_BUFFER);
return(1);
}
duk_ret_t ILibDuktape_DynamicBuffer_new(duk_context *ctx)
{
ILibDuktape_DynamicBuffer_data *data;
int initSize = 4096;
if (duk_get_top(ctx) != 0)
{
initSize = duk_require_int(ctx, 0);
}
duk_push_object(ctx); // [stream]
duk_push_fixed_buffer(ctx, sizeof(ILibDuktape_DynamicBuffer_data));
data = (ILibDuktape_DynamicBuffer_data*)Duktape_GetBuffer(ctx, -1, NULL);
memset(data, 0, sizeof(ILibDuktape_DynamicBuffer_data));
duk_put_prop_string(ctx, -2, "\xFF_buffer");
data->bufferLen = initSize;
data->buffer = (char*)malloc(initSize);
ILibDuktape_DuplexStream_InitEx(ctx, ILibDuktape_DynamicBuffer_WriteSink, ILibDuktape_DynamicBuffer_EndSink, NULL, NULL, ILibDuktape_DynamicBuffer_unshift, data);
ILibDuktape_EventEmitter_CreateEventEx(ILibDuktape_EventEmitter_GetEmitter(ctx, -1), "readable");
ILibDuktape_CreateInstanceMethod(ctx, "read", ILibDuktape_DynamicBuffer_read, DUK_VARARGS);
ILibDuktape_CreateFinalizer(ctx, ILibDuktape_DynamicBuffer_Finalizer);
ILibDuktape_ValidateHeapPointer(ctx, -1);
return(1);
}
void ILibDuktape_DynamicBuffer_Push(duk_context *ctx, void *chain)
{
duk_push_c_function(ctx, ILibDuktape_DynamicBuffer_new, DUK_VARARGS);
}
void ILibDuktape_Polyfills_Init(duk_context *ctx)
{
ILibDuktape_ModSearch_AddHandler(ctx, "queue", ILibDuktape_Queue_Push);
ILibDuktape_ModSearch_AddHandler(ctx, "DynamicBuffer", ILibDuktape_DynamicBuffer_Push);
// Global Polyfills
duk_push_global_object(ctx); // [g]
ILibDuktape_Polyfills_String(ctx);
ILibDuktape_Polyfills_Buffer(ctx);
ILibDuktape_Polyfills_Console(ctx);
ILibDuktape_Polyfills_byte_ordering(ctx);
ILibDuktape_Polyfills_timer(ctx);
ILibDuktape_CreateInstanceMethod(ctx, "addModule", ILibDuktape_Polyfills_addModule, 2);
duk_pop(ctx); // ...
}
#ifdef __DOXY__
/*!
\brief String
*/
class String
{
public:
/*!
\brief Finds a String within another String
\param str \<String\> Substring to search for
\return <Integer> Index of where the string was found. -1 if not found
*/
Integer indexOf(str);
/*!
\brief Extracts a String from a String.
\param startIndex <Integer> Starting index to extract
\param length <Integer> Number of characters to extract
\return \<String\> extracted String
*/
String substr(startIndex, length);
/*!
\brief Extracts a String from a String.
\param startIndex <Integer> Starting index to extract
\param endIndex <Integer> Ending index to extract
\return \<String\> extracted String
*/
String splice(startIndex, endIndex);
/*!
\brief Split String into substrings
\param str \<String\> Delimiter to split on
\return Array of Tokens
*/
Array<String> split(str);
/*!
\brief Determines if a String starts with the given substring
\param str \<String\> substring
\return <boolean> True, if this String starts with the given substring
*/
boolean startsWith(str);
};
/*!
\brief Instances of the Buffer class are similar to arrays of integers but correspond to fixed-sized, raw memory allocations.
*/
class Buffer
{
public:
/*!
\brief Create a new Buffer instance of the specified number of bytes
\param size <integer>
\return \<Buffer\> new Buffer instance
*/
Buffer(size);
/*!
\brief Returns the amount of memory allocated in bytes
*/
integer length;
/*!
\brief Creates a new Buffer instance from an encoded String
\param str \<String\> encoded String
\param encoding \<String\> Encoding. Can be either 'base64' or 'hex'
\return \<Buffer\> new Buffer instance
*/
static Buffer from(str, encoding);
/*!
\brief Decodes Buffer to a String
\param encoding \<String\> Optional. Can be either 'base64' or 'hex'. If not specified, will just encode as an ANSI string
\param start <integer> Optional. Starting offset. <b>Default:</b> 0
\param end <integer> Optional. Ending offset (not inclusive) <b>Default:</b> buffer length
\return \<String\> Encoded String
*/
String toString([encoding[, start[, end]]]);
/*!
\brief Returns a new Buffer that references the same memory as the original, but offset and cropped by the start and end indices.
\param start <integer> Where the new Buffer will start. <b>Default:</b> 0
\param end <integer> Where the new Buffer will end. (Not inclusive) <b>Default:</b> buffer length
\return \<Buffer\>
*/
Buffer slice([start[, end]]);
};
/*!
\brief Console
*/
class Console
{
public:
/*!
\brief Serializes the input parameters to the Console Display
\param args <any>
*/
void log(...args);
};
/*!
\brief Global Timer Methods
*/
class Timers
{
public:
/*!
\brief Schedules the "immediate" execution of the callback after I/O events' callbacks.
\param callback <func> Function to call at the end of the event loop
\param args <any> Optional arguments to pass when the callback is called
\return Immediate for use with clearImmediate().
*/
Immediate setImmediate(callback[, ...args]);
/*!
\brief Schedules execution of a one-time callback after delay milliseconds.
\param callback <func> Function to call when the timeout elapses
\param args <any> Optional arguments to pass when the callback is called
\return Timeout for use with clearTimeout().
*/
Timeout setTimeout(callback, delay[, ...args]);
/*!
\brief Schedules repeated execution of callback every delay milliseconds.
\param callback <func> Function to call when the timer elapses
\param args <any> Optional arguments to pass when the callback is called
\return Timeout for use with clearInterval().
*/
Timeout setInterval(callback, delay[, ...args]);
/*!
\brief Cancels a Timeout returned by setTimeout()
\param timeout Timeout
*/
void clearTimeout(timeout);
/*!
\brief Cancels a Timeout returned by setInterval()
\param interval Timeout
*/
void clearInterval(interval);
/*!
\brief Cancels an Immediate returned by setImmediate()
\param immediate Immediate
*/
void clearImmediate(immediate);
/*!
\brief Scheduled Timer
*/
class Timeout
{
public:
};
/*!
\implements Timeout
\brief Scheduled Immediate
*/
class Immediate
{
public:
};
};
/*!
\brief Global methods for byte ordering manipulation
*/
class BytesOrdering
{
public:
/*!
\brief Converts 2 bytes from network order to host order
\param buffer \<Buffer\> bytes to convert
\param offset <integer> offset to start
\return <integer> host order value
*/
static integer ntohs(buffer, offset);
/*!
\brief Converts 4 bytes from network order to host order
\param buffer \<Buffer\> bytes to convert
\param offset <integer> offset to start
\return <integer> host order value
*/
static integer ntohl(buffer, offset);
/*!
\brief Writes 2 bytes in network order
\param buffer \<Buffer\> Buffer to write to
\param offset <integer> offset to start writing
\param val <integer> host order value to write
*/
static void htons(buffer, offset, val);
/*!
\brief Writes 4 bytes in network order
\param buffer \<Buffer\> Buffer to write to
\param offset <integer> offset to start writing
\param val <integer> host order value to write
*/
static void htonl(buffer, offset, val);
};
#endif