#include #include #include #include "maplec.h" #include "duktape.h" /* --- EXPORT_DECL macro from official example --- */ #if !defined(EXPORT_DECL) #ifdef _MSC_VER #define EXPORT_DECL __declspec(dllexport) #else #define EXPORT_DECL #endif #endif /* --- the SheetJS + Duktape demo cover these machinations --- */ #define FAIL_LOAD { \ duk_push_undefined(ctx); \ perror("Error in load_file"); \ return 1; \ } static char *read_file(const char *filename, size_t *sz) { FILE *f = fopen(filename, "rb"); if(!f) return NULL; long fsize; { fseek(f, 0, SEEK_END); fsize = ftell(f); fseek(f, 0, SEEK_SET); } char *buf = (char *)malloc(fsize * sizeof(char)); *sz = fread((void *) buf, 1, fsize, f); fclose(f); return buf; } static duk_int_t eval_file(duk_context *ctx, const char *filename) { size_t len; char *buf = read_file(filename, &len); if(!buf) FAIL_LOAD duk_push_lstring(ctx, (const char *)buf, (duk_size_t)len); duk_int_t retval = duk_peval(ctx); duk_pop(ctx); return retval; } static duk_int_t load_file(duk_context *ctx, const char *filename, const char *var) { size_t len; char *buf = read_file(filename, &len); if(!buf) FAIL_LOAD duk_push_external_buffer(ctx); duk_config_buffer(ctx, -1, buf, len); duk_put_global_string(ctx, var); return 0; } static duk_int_t save_file(duk_context *ctx, const char *filename, const char *var) { duk_get_global_string(ctx, var); duk_size_t sz; char *buf = (char *)duk_get_buffer_data(ctx, -1, &sz); if(!buf) return 1; FILE *f = fopen(filename, "wb"); fwrite(buf, 1, sz, f); fclose(f); return 0; } #define FAIL_DUK(cmd) { \ const char *errmsg = duk_safe_to_string(ctx, -1); \ duk_destroy_heap(ctx); \ MapleRaiseError2(kv, "error in %1 : %2", ToMapleString(kv, cmd), ToMapleString(kv, errmsg)); \ return NULL; \ } #define DOIT(cmd) duk_eval_string_noresult(ctx, cmd); /* SheetToXLSX function */ EXPORT_DECL ALGEB M_DECL SheetToXLSX( MKernelVector kv, ALGEB *args ) { duk_int_t res = 0; /* get filename */ if(MapleNumArgs(kv, (ALGEB)args) != 1) { MapleRaiseError(kv, "must specify a filename"); return NULL; } if(!IsMapleString(kv, args[1])) { MapleRaiseError(kv, "filename must be a string"); return NULL; } const char *filename = MapleToString(kv, args[1]); /* initialize duktape */ duk_context *ctx = duk_create_heap_default(); /* duktape does not expose a standard "global" by default */ DOIT("var global = (function(){ return this; }).call(null);"); /* load SheetJS library */ res = eval_file(ctx, "shim.min.js"); if(res != 0) FAIL_DUK("shim load") res = eval_file(ctx, "xlsx.full.min.js"); if(res != 0) FAIL_DUK("library load") /* read file */ res = load_file(ctx, filename, "buf"); if(res != 0) FAIL_DUK("file load") printf("Loaded file %s\n", filename); /* parse workbook and write to XLSX */ DOIT("wb = XLSX.read(buf.slice(0, buf.length), {type:'buffer'});"); DOIT("newbuf = (XLSX.write(wb, {type:'array', bookType:'xlsx'}));");\ /* write file */ res = save_file(ctx, "sheetjsw.xlsx", "newbuf");\ if(res != 0) FAIL_DUK("save sheetjsw.xlsx") /* return filename */ return ToMapleString(kv, "sheetjsw.xlsx"); }