diff --git a/src/vm_builtins.c b/src/vm_builtins.c index d61d9e3c..b25b0937 100644 --- a/src/vm_builtins.c +++ b/src/vm_builtins.c @@ -6385,7 +6385,49 @@ static RValue builtin_buffer_save(MAYBE_UNUSED VMContext* ctx, RValue* args, MAY return RValue_makeUndefined(); } -STUB_RETURN_ZERO(buffer_base64_encode) +static RValue builtin_buffer_base64_encode(MAYBE_UNUSED VMContext* ctx, RValue* args, MAYBE_UNUSED int32_t argCount) { + Runner* runner = ctx->runner; + if (3 > argCount) return RValue_makeOwnedString(safeStrdup("")); + + int32_t id = RValue_toInt32(args[0]); + GmlBuffer* buf = gmlBufferGet(runner, id); + if (buf == nullptr) return RValue_makeOwnedString(safeStrdup("")); + + int32_t offset = RValue_toInt32(args[1]); + size_t size = RValue_toInt32(args[2]); + + int32_t maxBoundary = (buf->type == GML_BUFFER_GROW) ? buf->usedSize : buf->size; + + if (offset < 0 || offset >= maxBoundary || size <= 0) { + return RValue_makeOwnedString(safeStrdup("")); + } + + if (offset + size > (size_t)maxBoundary) { + size = (size_t)(maxBoundary - offset); + } + + char* out = safeMalloc(BASE64_ENCODE_OUT_SIZE(size)); + base64_encode((const unsigned char*) buf->data + offset, size, out); + return RValue_makeOwnedString(out); +} + +static RValue builtin_buffer_base64_decode(MAYBE_UNUSED VMContext* ctx, RValue* args, MAYBE_UNUSED int32_t argCount) { + Runner* runner = ctx->runner; + if (2 > argCount) return RValue_makeOwnedString(safeStrdup("")); + char* input = RValue_toString(args[1]); + unsigned int inLen = (unsigned int) strlen(input); + size_t outLen = BASE64_DECODE_OUT_SIZE(inLen); + char* out = safeMalloc(outLen); + base64_decode((const unsigned char*) input, inLen, out); + free(input); + int32_t id = gmlBufferCreate(runner, outLen, GML_BUFFER_GROW, 1); + GmlBuffer* buf = gmlBufferGet(runner, id); + free(buf->data); + buf->data = out; + buf->size = outLen; + buf->usedSize = outLen; + return RValue_makeReal((GMLReal) id); +} static RValue builtin_base64_encode(MAYBE_UNUSED VMContext* ctx, RValue* args, MAYBE_UNUSED int32_t argCount) { if (1 > argCount) return RValue_makeOwnedString(safeStrdup("")); @@ -11292,6 +11334,7 @@ void VMBuiltins_registerAll(VMContext* ctx) { VM_registerBuiltin(ctx, "buffer_load", builtin_buffer_load); VM_registerBuiltin(ctx, "buffer_save", builtin_buffer_save); VM_registerBuiltin(ctx, "buffer_base64_encode", builtin_buffer_base64_encode); + VM_registerBuiltin(ctx, "buffer_base64_decode", builtin_buffer_base64_decode); VM_registerBuiltin(ctx, "base64_encode", builtin_base64_encode); VM_registerBuiltin(ctx, "base64_decode", builtin_base64_decode); VM_registerBuiltin(ctx, "buffer_md5", builtin_buffer_md5);