/
Genesis-1.0p36-DEV/
Genesis-1.0p36-DEV/bin/
Genesis-1.0p36-DEV/doc/
Genesis-1.0p36-DEV/etc/
Genesis-1.0p36-DEV/src/data/
/*
// Full copyright information is available in the file ../doc/CREDITS
//
// VEIL packets buffer manipulation module
//
// look at http://www.cold.org/VEIL/ for more information.
//
*/

#define NATIVE_MODULE "$buffer"

#define VEIL_C

#include "veil.h"

module_t veil_module = {YES, init_veil, YES, uninit_veil};

#define VEIL_P_PUSH      1
#define VEIL_P_ABORT     2
#define VEIL_P_CLOSE     4
#define VEIL_P_OPEN      8
#define VEIL_P_UNDF1     16
#define VEIL_P_UNDF2     32
#define VEIL_P_UNDF3     64
#define VEIL_P_UNDF4     128

/*
// 1 byte bitfield flags
// 2 bytes channel id
// 2 bytes length
*/

#define HEADER_SIZE    5

void init_veil(Int argc, char ** argv) {
    pabort_id = ident_get("abort");
    pclose_id = ident_get("close");
    popen_id  = ident_get("open");
}

void uninit_veil(void) {
    ident_discard(pabort_id);
    ident_discard(pclose_id);
    ident_discard(popen_id);
}

/*
// -------------------------------------------------------------------
// In ColdC we represent a VEIL packet as:
//
//       [1|0, 'abort|'close|'open|0, id, `[]]
//
// The first argument represents the push bit, and the end of a message.
// id is an integer.
*/

/*
// -------------------------------------------------------------------
// internal function for buffer -> VEIL packet
*/
cList * buf_to_veil_packets(cBuf * buf) {
    Int             flags,
                    channel,
                    length,
                    blen;
    cBuf          * databuf,
                  * incomplete;
    cData           d,
                  * list;
    cList         * output,
                  * packet;
    unsigned char * cbuf;

    output = list_new(0);
    blen = buf->len;
    cbuf = buf->s;

    forever {
        /* 5 bytes will give us the header, we check length again after
           that, because the header gives us the data length */
        if (blen < HEADER_SIZE)
            break;

        /* grab the bit flags */
        flags = (Int) cbuf[0];

        /* get the Channel ID and data length */
        channel = (Int) (((int) cbuf[1] * 256) + ((int) cbuf[2]));
        length = (Int) (((int) cbuf[3] * 256) + ((int) cbuf[4]));

        if (length > (blen - HEADER_SIZE))
            break;

        /* copy the data segment of the packet to the databuf */
        databuf = buffer_new(length);
        cbuf += HEADER_SIZE;
        MEMCPY(databuf->s, cbuf, length);
        cbuf += (length);
        blen -= (length + HEADER_SIZE);

        /* create the packet list, add it to the output list */
        packet = list_new(4);
        list = list_empty_spaces(packet, 4);
        list[0].type = INTEGER;
        list[0].u.val = (flags & VEIL_P_PUSH) ? 1 : 0;

        /* give abort precedence */
        if (flags & VEIL_P_ABORT) {
            list[1].type     = SYMBOL;
            list[1].u.symbol = pabort_id;
        } else if (flags & VEIL_P_CLOSE) {
            list[1].type     = SYMBOL;
            list[1].u.symbol = pclose_id;
        } else if (flags & VEIL_P_OPEN) {
            list[1].type     = SYMBOL;
            list[1].u.symbol = popen_id;
        } else {
            list[1].type  = INTEGER;
            list[1].u.val = 0;
        }

        list[2].type = INTEGER;
        list[2].u.val = channel;

        list[3].type = BUFFER;
        list[3].u.buffer = buffer_dup(databuf);

        /* add it to the list */
        d.type = LIST;
        d.u.list = packet;
        output = list_add(output, &d);

        buffer_discard(databuf);
        list_discard(packet);
    }

    /* add the incomplete buffer to the end */
    incomplete = buffer_new(blen);
    if (blen > 0)
        MEMMOVE(incomplete->s, cbuf, blen);
    d.type = BUFFER;
    d.u.buffer = incomplete;
    output = list_add(output, &d);
    buffer_discard(incomplete);

    return output;
}

/*
// -------------------------------------------------------------------
// Convert from a buffer to the standard 'VEIL packet' format
*/
NATIVE_METHOD(to_veil_pkts) {
    cBuf * buf;
    cList * packets;

    INIT_1_OR_2_ARGS(BUFFER, BUFFER);

    if (argc == 1) {
        buf = buffer_dup(_BUF(ARG1));
    } else {
        /* if they sent us a second argument, concatenate it on the end */
        buf = buffer_append(buffer_dup(_BUF(ARG1)), _BUF(ARG2));
    }

    packets = buf_to_veil_packets(buf);

    buffer_discard(buf);

    CLEAN_RETURN_LIST(packets);
}

/*
// -------------------------------------------------------------------
// Convert to a buffer from the standard 'VEIL packet' format
//
// in leiu of speed, we do not do COMPLETE checking on every argument
// sent to the packet, just make sure you do it right
*/
NATIVE_METHOD(from_veil_pkts) {
    cData       * d,
                * pa;
    cBuf        * out,
                * header;
    cList       * p,
                * packets;
    Int           len;

    INIT_1_ARG(LIST);

    header = buffer_new(HEADER_SIZE);

    out = buffer_new(0);
    packets = LIST1;

    for (d = list_first(packets); d; d = list_next(packets, d)) {
        if (d->type != LIST)
            THROW((type_id, "Packets submitted in an invalid format"));
        p = d->u.list;
        pa = list_first(p);
        if (!pa || pa->type != INTEGER)
            THROW((type_id, "Packet submitted in an invalid format"));

        header->s[0] = (unsigned char) 0;
        if (pa->u.val)
            header->s[0] |= VEIL_P_PUSH;

        pa = list_next(p, pa);
        if (!pa)
            THROW((type_id, "Not enough elements in the packet!"));
        if (pa->type == SYMBOL) {
            if (pa->u.symbol == pabort_id)
                header->s[0] |= VEIL_P_ABORT;
            else if (pa->u.symbol == pclose_id)
                header->s[0] |= VEIL_P_CLOSE;
            else if (pa->u.symbol == popen_id)
                header->s[0] |= VEIL_P_OPEN;
        }

        pa = list_next(p, pa);
        if (!pa || pa->type != INTEGER)
            THROW((type_id, "Packet submitted in an invalid format"));

        header->s[1] = (unsigned char) pa->u.val/256;
        header->s[2] = (unsigned char) pa->u.val%256;

        pa = list_next(p, pa);
        if (!pa || pa->type != BUFFER)
            THROW((type_id, "Packet submitted in an invalid format"));

        header->s[3] = (unsigned char) pa->u.buffer->len/256;
        header->s[4] = (unsigned char) pa->u.buffer->len%256;

        len = out->len + header->len + pa->u.buffer->len - 2;
        out = (cBuf *) erealloc(out, sizeof(cBuf) + len);
        MEMCPY(out->s + out->len, header->s, header->len);
        out->len += header->len;
        MEMCPY(out->s + out->len, pa->u.buffer->s, pa->u.buffer->len);
        out->len += pa->u.buffer->len;
    }

    CLEAN_RETURN_BUFFER(out);
}