#!/usr/bin/env python3 lib = "libduktape.207.20700.so" from ctypes import CDLL, byref, string_at, c_int, c_void_p, c_char_p, c_size_t duk = CDLL(lib) def str_to_c(s): b = s.encode("utf8") return [c_char_p(b), len(b)] def duk_create_heap_default(): duk.duk_create_heap.restype = c_void_p return duk.duk_create_heap(None, None, None, None, None) def duk_eval_string_noresult(ctx, cmd): [s, l] = str_to_c(cmd) return duk.duk_eval_raw(ctx, s, l, 1 | (1<<3) | (1<<9) | (1<<10) | (1<<8) | (1<<11) ) def duk_eval_string(ctx, cmd): [s, l] = str_to_c(cmd) return duk.duk_eval_raw(ctx, s, l, 0 | (1<<3) | (1<<9) | (1<<10) | (1<<11) ) def duk_peval(ctx): return duk.duk_eval_raw(ctx, None, 0, 1 | (1<<3) | (1<<7) | (1<<11) ) def duk_get_string(ctx, idx): duk.duk_get_string.restype = c_char_p retval = duk.duk_get_string(ctx, idx) return retval.decode("utf8") def eval_file(ctx, path): with open(path, "r") as f: code = f.read() [s, l] = str_to_c(code) duk.duk_push_lstring(ctx, s, l) retval = duk_peval(ctx) duk.duk_pop(ctx) return retval def load_file(ctx, path, var): with open(path, "rb") as f: data = f.read() ptr = c_char_p(data) duk.duk_push_buffer_raw(ctx, 0, 1 | 2) duk.duk_config_buffer(ctx, -1, ptr, len(data)) duk.duk_put_global_string(ctx, str_to_c(var)[0]) return data def save_file(ctx, path, var): duk.duk_get_global_string(ctx, str_to_c(var)[0]) sz = c_size_t() duk.duk_get_buffer_data.restype = c_void_p buf = duk.duk_get_buffer_data(ctx, -1, byref(sz)) s = string_at(buf, sz.value) with open(path, "wb") as f: f.write(s) def process(path): # initialize context = duk_create_heap_default() ctx = c_void_p(context) def DOIT(cmd): return duk_eval_string_noresult(ctx, cmd) # duktape does not expose a standard "global" by default DOIT("var global = (function(){ return this; }).call(null);") # load library eval_file(ctx, "shim.min.js") eval_file(ctx, "xlsx.full.min.js") # get version string duk_eval_string(ctx, "XLSX.version") print("SheetJS Library Version %s" % (duk_get_string(ctx, -1))) duk.duk_pop(ctx) # read file # NOTE: data is captured here to avoid GC data = load_file(ctx, path, "buf") print("Loaded file %s" % (path)) # parse workbook DOIT("wb = XLSX.read(buf.slice(0, buf.length));") DOIT("ws = wb.Sheets[wb.SheetNames[0]]") # print CSV duk_eval_string(ctx, "XLSX.utils.sheet_to_csv(ws)") print(duk_get_string(ctx, -1)) duk.duk_pop(ctx) DOIT("newbuf = (XLSX.write(wb, {type:'buffer', bookType:'xlsb'}));") save_file(ctx, "sheetjsw.xlsb", "newbuf") duk.duk_destroy_heap(ctx) return 0 if("__main__" == __name__): from sys import argv process(argv[1])