/* Copyright (c) 2026 Juhapekka Piiroinen * All Rights Reserved. * AmoosedWeb project: https://amoosed.com */ #include "AmoosedWeb/CompilerPreviewC.h" #include #include #include #include #ifdef _WIN32 #include #include #include #include #define AMW_WRITE _write #define AMW_CLOSE _close #define AMW_UNLINK _unlink #else #include #include #define AMW_WRITE write #define AMW_CLOSE close #define AMW_UNLINK unlink #endif static void clear_bytes(void* data, size_t length) { volatile unsigned char* bytes = (volatile unsigned char*)data; while (length--) *bytes++ = 0; } static int hex_digit(unsigned char value) { if (value >= '0' && value <= '9') return value - '0'; if (value >= 'a' && value <= 'f') return value - 'a' + 10; if (value >= 'A' && value <= 'F') return value - 'A' + 10; return -1; } static int read_key(const char* path, unsigned char key[32]) { unsigned char text[68] = {0}; FILE* file = fopen(path, "rb"); size_t length, i; if (!file) return 0; length = fread(text, 1, sizeof(text), file); { int valid_read = !ferror(file) && feof(file); int closed = fclose(file); if (!valid_read || closed) { clear_bytes(text, sizeof(text)); return 0; } } while (length && (text[length - 1] == '\n' || text[length - 1] == '\r')) --length; if (length != 64) { clear_bytes(text, sizeof(text)); return 0; } for (i = 0; i < 32; ++i) { int high = hex_digit(text[2 * i]), low = hex_digit(text[2 * i + 1]); if (high < 0 || low < 0) { clear_bytes(text, sizeof(text)); clear_bytes(key, 32); return 0; } key[i] = (unsigned char)((high << 4) | low); } clear_bytes(text, sizeof(text)); return 1; } static unsigned char* read_payload(const char* path, size_t* length) { FILE* file = fopen(path, "rb"); long size; unsigned char* data; if (!file) return NULL; if (fseek(file, 0, SEEK_END) || (size = ftell(file)) <= 0 || size > 4068 || fseek(file, 0, SEEK_SET)) { fclose(file); return NULL; } data = (unsigned char*)malloc((size_t)size); if (!data) { fclose(file); return NULL; } { int valid_read = fread(data, 1, (size_t)size, file) == (size_t)size; int closed = fclose(file); if (!valid_read || closed) { free(data); return NULL; } } *length = (size_t)size; return data; } static int create_output(const char* path, const unsigned char* data, size_t length) { int fd, ok = 1; size_t offset = 0; #ifdef _WIN32 if (_sopen_s(&fd, path, _O_WRONLY | _O_CREAT | _O_EXCL | _O_BINARY, _SH_DENYNO, _S_IREAD | _S_IWRITE)) return 0; #else fd = open(path, O_WRONLY | O_CREAT | O_EXCL, 0600); if (fd < 0) return 0; #endif while (offset < length) { int written = (int)AMW_WRITE(fd, data + offset, (unsigned int)(length - offset)); if (written <= 0) { ok = 0; break; } offset += (size_t)written; } if (AMW_CLOSE(fd)) ok = 0; if (!ok) AMW_UNLINK(path); return ok; } int main(int argc, char** argv) { unsigned char key[32] = {0}; unsigned char *payload = NULL, *wav = NULL; size_t payload_length = 0; uint64_t required = 0; uint64_t allocated = 0, capabilities = 0; uint32_t revision = 0; char error[192] = {0}; int32_t status; int result = 1; if (argc != 4) { fputs("Usage: native-c-audio-encode PAYLOAD_FILE MEDIA_KEY_HEX_FILE NEW_CARRIER.wav\n", stderr); return 2; } if (amwc_preview_query(&revision, &capabilities) != AMWC_PREVIEW_OK || revision != AMWC_PREVIEW_ABI_REVISION || !(capabilities & AMWC_PREVIEW_CAP_AUDIO_FILE)) { fputs("This library does not support the required compiler audio API.\n", stderr); return 1; } if (!read_key(argv[2], key) || !(payload = read_payload(argv[1], &payload_length))) { fputs("Cannot read the media key or 1-4068 byte payload.\n", stderr); goto done; } status = amwc_preview_audio_encode_file(payload, payload_length, key, sizeof(key), NULL, 0, &required, error, sizeof(error)); if (status != AMWC_PREVIEW_OK || required < 44 || required > 128u * 1024u * 1024u) goto encode_failed; allocated = required; wav = (unsigned char*)malloc((size_t)allocated); if (!wav) goto done; status = amwc_preview_audio_encode_file(payload, payload_length, key, sizeof(key), wav, allocated, &required, error, sizeof(error)); if (status != AMWC_PREVIEW_OK || required != allocated) goto encode_failed; if (!create_output(argv[3], wav, (size_t)required)) { fputs("Output exists or cannot be written.\n", stderr); goto done; } result = 0; goto done; encode_failed: fprintf(stderr, "Audio encode failed (%d): %s\n", (int)status, error); done: clear_bytes(key, sizeof(key)); if (payload) { clear_bytes(payload, payload_length); free(payload); } free(wav); return result; }