/* Entry points for johnmcm.com's Microsoft Works Viewer: libwps and * librevenge compiled to WebAssembly. Modelled on the revenge module's * binding (wasm-src/revenge/src/binding.cpp). * * SPDX-License-Identifier: MPL-2.0 * * Every entry point returns a plain object instead of throwing, so the page * never handles a WebAssembly.Exception. * * view = inputBuffer(n) Uint8Array over n bytes of wasm memory; fill it at once * d = detect() { ok, kind, creator, encrypted, needEncoding } * kind: 0 text, 1 spreadsheet, 2 database * r = parse(password, enc) { ok, result, kind, json } result: libwps::WPSResult * release() frees the input */ #include #include #include #include #include #include #include #include #include #include "recorder.h" using emscripten::val; namespace { unsigned char *g_input = nullptr; size_t g_size = 0; void release() { std::free(g_input); g_input = nullptr; g_size = 0; } val fail(const std::string &msg) { val r = val::object(); r.set("ok", false); r.set("error", msg); return r; } val inputBuffer(unsigned size) { release(); if (!size) return val::null(); g_input = static_cast(std::malloc(size)); if (!g_input) return val::null(); g_size = size; return val(emscripten::typed_memory_view(size, g_input)); } val detect() { if (!g_input) return fail("no input"); try { librevenge::RVNGStringStream input(g_input, static_cast(g_size)); libwps::WPSKind kind = libwps::WPS_TEXT; libwps::WPSCreator creator = libwps::WPS_MSWORKS; bool needEncoding = false; libwps::WPSConfidence confidence = libwps::WPSDocument::isFileFormatSupported(&input, kind, creator, needEncoding); val r = val::object(); r.set("ok", confidence != libwps::WPS_CONFIDENCE_NONE); r.set("kind", static_cast(kind)); r.set("creator", static_cast(creator)); r.set("encrypted", confidence == libwps::WPS_CONFIDENCE_SUPPORTED_ENCRYPTION); r.set("needEncoding", needEncoding); return r; } catch (const std::exception &e) { return fail(std::string("C++ exception: ") + e.what()); } catch (...) { return fail("unknown C++ exception"); } } val parse(std::string password, std::string encoding) { if (!g_input) return fail("no input"); try { librevenge::RVNGStringStream input(g_input, static_cast(g_size)); libwps::WPSKind kind = libwps::WPS_TEXT; libwps::WPSCreator creator = libwps::WPS_MSWORKS; bool needEncoding = false; if (libwps::WPSDocument::isFileFormatSupported(&input, kind, creator, needEncoding) == libwps::WPS_CONFIDENCE_NONE) return fail("unsupported"); input.seek(0, librevenge::RVNG_SEEK_SET); libwps::WPSResult result; std::string json; if (kind == libwps::WPS_TEXT) { jm::TextRecorder rec; result = libwps::WPSDocument::parse(&input, &rec, password.c_str(), encoding.c_str()); json = rec.result(); } else { jm::SheetRecorder rec; result = libwps::WPSDocument::parse(&input, &rec, password.c_str(), encoding.c_str()); json = rec.result(); } val r = val::object(); r.set("ok", result == libwps::WPS_OK); r.set("result", static_cast(result)); r.set("kind", static_cast(kind)); r.set("json", json); return r; } catch (const std::exception &e) { return fail(std::string("C++ exception: ") + e.what()); } catch (...) { return fail("unknown C++ exception"); } } } // anonymous namespace EMSCRIPTEN_BINDINGS(wps) { emscripten::function("inputBuffer", &inputBuffer); emscripten::function("detect", &detect); emscripten::function("parse", &parse); emscripten::function("release", &release); }