// SPDX-License-Identifier: AGPL-3.0-only
// Heimdall is a defensive sandbox. The ONLY C written for the verify-bundle
// guest's OpenZL decoder (wasm32 builds; native builds link openzl-sys-rs):
//
// 1. hzl_frame_size / hzl_decode: ZL_getDecompressedSize and ZL_decompress
// behind a scalar-only ABI (ZL_Report is a struct returned by value; the
// guest's Rust never sees it).
// 2. The few libc symbols OpenZL's decoder references that are not memory
// functions: its logging (fprintf/vfprintf/fputc/stderr) and its error-
// message formatting (vsnprintf) — the guest has no stdio, so they write
// nothing — and abort, which traps.
//
// malloc/calloc/realloc/free are the guest's Rust allocator (src/zl.rs);
// memcpy/memmove/memset come from Rust's compiler-builtins. Everything is
// compiled into the module: the guest component imports nothing but the WIT.
#include <stdarg.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include "openzl/zl_decompress.h"
#include "openzl/zl_errors.h"
// 0 = ok and *out set; otherwise the ZL_ErrorCode.
int hzl_frame_size(const void* src, size_t src_len, uint64_t* out)
{
ZL_Report r = ZL_getDecompressedSize(src, src_len);
if (ZL_isError(r)) {
return (int)ZL_errorCode(r);
}
*out = (uint64_t)ZL_validResult(r);
return 0;
}
int hzl_decode(void* dst, size_t cap, const void* src, size_t src_len, size_t* written)
{
ZL_Report r = ZL_decompress(dst, cap, src, src_len);
if (ZL_isError(r)) {
return (int)ZL_errorCode(r);
}
*written = ZL_validResult(r);
return 0;
}
const char* hzl_error_name(int code)
{
return ZL_ErrorCode_toString((ZL_ErrorCode)code);
}
// ---- the libc the decoder references (no stdio in the guest) ----
FILE* const stderr = NULL;
int vfprintf(FILE* restrict f, const char* restrict fmt, va_list ap)
{
(void)f;
(void)fmt;
(void)ap;
return 0;
}
int fprintf(FILE* restrict f, const char* restrict fmt, ...)
{
(void)f;
(void)fmt;
return 0;
}
int fputc(int c, FILE* f)
{
(void)f;
return c;
}
int vsnprintf(char* restrict buf, size_t n, const char* restrict fmt, va_list ap)
{
(void)fmt;
(void)ap;
if (n > 0) {
buf[0] = '\0';
}
return 0;
}
_Noreturn void abort(void)
{
__builtin_trap();
}