dtob-sys 0.1.0

Raw FFI bindings to the dtob C library (encoder + decoder).
Documentation
#include "cli.h"
#include <curl/curl.h>

typedef struct {
    uint8_t *buf;
    size_t   len;
    size_t   cap;
} CurlBuf;

static size_t write_cb(void *data, size_t size, size_t nmemb, void *userp)
{
    CurlBuf *b = userp;
    size_t total = size * nmemb;
    if (b->len + total >= b->cap) {
        b->cap = (b->len + total) * 2 + 4096;
        uint8_t *tmp = realloc(b->buf, b->cap);
        if (!tmp) return 0;
        b->buf = tmp;
    }
    memcpy(b->buf + b->len, data, total);
    b->len += total;
    return total;
}

uint8_t *fetch_url_bytes_ex(const char *url, size_t *out_len, char **effective_url_out)
{
    CURL *curl = curl_easy_init();
    if (!curl) return NULL;

    CurlBuf b = { malloc(65536), 0, 65536 };
    if (!b.buf) { curl_easy_cleanup(curl); return NULL; }

    curl_easy_setopt(curl, CURLOPT_URL, url);
    curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
    curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
    curl_easy_setopt(curl, CURLOPT_USERAGENT,
        "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) "
        "AppleWebKit/537.36 (KHTML, like Gecko) "
        "Chrome/120.0.0.0 Safari/537.36");
    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_cb);
    curl_easy_setopt(curl, CURLOPT_WRITEDATA, &b);

    CURLcode res = curl_easy_perform(curl);
    long http_code = 0;
    curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_code);
    if (effective_url_out) {
        char *eff = NULL;
        curl_easy_getinfo(curl, CURLINFO_EFFECTIVE_URL, &eff);
        *effective_url_out = eff ? strdup(eff) : NULL;
    }
    curl_easy_cleanup(curl);

    if (res != CURLE_OK) {
        fprintf(stderr, "curl: %s\n", curl_easy_strerror(res));
        free(b.buf);
        return NULL;
    }
    if (http_code >= 400) {
        fprintf(stderr, "curl: HTTP %ld for %s\n", http_code, url);
        free(b.buf);
        return NULL;
    }

    *out_len = b.len;
    return b.buf;
}

uint8_t *fetch_url_bytes(const char *url, size_t *out_len)
{
    return fetch_url_bytes_ex(url, out_len, NULL);
}