189 lines
3.6 KiB
C++
189 lines
3.6 KiB
C++
// WASM-PROPOSAL Phase 3 — dynamic-loader core scaffold.
|
|
//
|
|
// This core owns the UCE heap, Request, DValue/UCEB1, and output buffer. The
|
|
// Phase 3 loader dynamically links a PIC side module generated in the same
|
|
// shape as UCE preprocessor output, sets its Request* context, and invokes its
|
|
// __uce_render entry.
|
|
|
|
#include <cstdlib>
|
|
#include <cstring>
|
|
#include <functional>
|
|
|
|
#include "../../src/lib/types.h"
|
|
#include "../../src/lib/dvalue.cpp"
|
|
|
|
extern "C" {
|
|
size_t uce_host_ctx_read(char* buf, size_t cap);
|
|
void uce_host_log(int level, const char* buf, size_t len);
|
|
}
|
|
|
|
extern "C" void phase3_core_print(const char* data, size_t len)
|
|
{
|
|
if(context && context->ob)
|
|
context->ob->write(data, len);
|
|
}
|
|
|
|
extern "C" void phase3_core_invoke_callback(void (*cb)(int), int value)
|
|
{
|
|
cb(value);
|
|
}
|
|
|
|
extern "C" void phase3_core_invoke_function(std::function<int(int)>* f, int value)
|
|
{
|
|
String out = "<p>fn=" + std::to_string((*f)(value)) + "</p>\n";
|
|
phase3_core_print(out.data(), out.size());
|
|
}
|
|
|
|
extern "C" intptr_t core_table_index_of_phase3_core_print()
|
|
{
|
|
return(reinterpret_cast<intptr_t>(phase3_core_print));
|
|
}
|
|
|
|
static Request g_request;
|
|
static ByteStream g_ob;
|
|
static String g_output;
|
|
|
|
SharedUnit::~SharedUnit() {}
|
|
|
|
String html_escape(String s)
|
|
{
|
|
String result;
|
|
for(char c : s)
|
|
{
|
|
switch(c)
|
|
{
|
|
case '&': result += "&"; break;
|
|
case '<': result += "<"; break;
|
|
case '>': result += ">"; break;
|
|
case '"': result += """; break;
|
|
case '\'': result += "'"; break;
|
|
default: result.push_back(c); break;
|
|
}
|
|
}
|
|
return(result);
|
|
}
|
|
|
|
String nibble(String div, String& haystack)
|
|
{
|
|
auto pos = haystack.find(div);
|
|
if(pos == String::npos)
|
|
{
|
|
auto result = haystack;
|
|
haystack.clear();
|
|
return(result);
|
|
}
|
|
auto result = haystack.substr(0, pos);
|
|
haystack.erase(0, pos + div.length());
|
|
return(result);
|
|
}
|
|
|
|
void Request::ob_start()
|
|
{
|
|
ob_stack.push_back(new ByteStream());
|
|
ob = ob_stack.back();
|
|
}
|
|
|
|
void Request::set_status(s32 code, String reason)
|
|
{
|
|
if(reason == "")
|
|
reason = code == 200 ? "OK" : "Status";
|
|
response_code = "HTTP/1.1 " + std::to_string(code) + " " + reason;
|
|
}
|
|
|
|
Request::~Request()
|
|
{
|
|
for(auto* stream : ob_stack)
|
|
delete stream;
|
|
ob_stack.clear();
|
|
}
|
|
|
|
static void phase3_clear_ob_stack()
|
|
{
|
|
for(auto* stream : g_request.ob_stack)
|
|
delete stream;
|
|
g_request.ob_stack.clear();
|
|
}
|
|
|
|
static void phase3_apply_context(DValue& root)
|
|
{
|
|
g_request.call = root;
|
|
g_request.params.clear();
|
|
DValue* params = root.key("params");
|
|
if(params)
|
|
{
|
|
params->each([&](const DValue& item, String key) {
|
|
g_request.params[key] = item.to_string();
|
|
});
|
|
}
|
|
}
|
|
|
|
extern "C" {
|
|
|
|
void* uce_alloc(size_t len)
|
|
{
|
|
return(malloc(len));
|
|
}
|
|
|
|
void uce_free(void* ptr)
|
|
{
|
|
free(ptr);
|
|
}
|
|
|
|
int uce_phase3_prepare()
|
|
{
|
|
context = &g_request;
|
|
phase3_clear_ob_stack();
|
|
g_ob.str("");
|
|
g_ob.clear();
|
|
g_request.ob = &g_ob;
|
|
g_request.out = "";
|
|
g_output = "";
|
|
|
|
size_t ctx_required = uce_host_ctx_read(0, 0);
|
|
if(ctx_required == 0)
|
|
return(10);
|
|
char* ctx_buf = (char*)malloc(ctx_required);
|
|
if(ctx_buf == 0)
|
|
return(11);
|
|
size_t ctx_len = uce_host_ctx_read(ctx_buf, ctx_required);
|
|
if(ctx_len != ctx_required)
|
|
{
|
|
free(ctx_buf);
|
|
return(12);
|
|
}
|
|
|
|
DValue decoded;
|
|
String error;
|
|
bool ok = ucb_decode(String(ctx_buf, ctx_len), decoded, &error);
|
|
free(ctx_buf);
|
|
if(!ok)
|
|
{
|
|
uce_host_log(3, error.data(), error.size());
|
|
return(20);
|
|
}
|
|
phase3_apply_context(decoded);
|
|
return(0);
|
|
}
|
|
|
|
Request* uce_phase3_request()
|
|
{
|
|
return(&g_request);
|
|
}
|
|
|
|
void uce_phase3_finish()
|
|
{
|
|
g_output = g_ob.str();
|
|
}
|
|
|
|
const char* uce_phase3_output_data()
|
|
{
|
|
return(g_output.data());
|
|
}
|
|
|
|
size_t uce_phase3_output_size()
|
|
{
|
|
return(g_output.size());
|
|
}
|
|
|
|
}
|