/* this is a file autogenerated by spice_codegen.py */
/*
  Copyright (C) 2013 Red Hat, Inc.

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.

  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Lesser General Public License for more details.

  You should have received a copy of the GNU Lesser General Public
  License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "test-marshallers.h"
#include <string.h>
#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
#include <spice/protocol.h>
#include <spice/macros.h>
#include <common/mem.h>

#ifdef _MSC_VER
#pragma warning(disable:4101)
#endif



#include <spice/start-packed.h>
typedef struct SPICE_ATTR_PACKED {
    int16_t v;
} int16_unaligned_t;
typedef struct SPICE_ATTR_PACKED {
    uint16_t v;
} uint16_unaligned_t;
typedef struct SPICE_ATTR_PACKED {
    int32_t v;
} int32_unaligned_t;
typedef struct SPICE_ATTR_PACKED {
    uint32_t v;
} uint32_unaligned_t;
typedef struct SPICE_ATTR_PACKED {
    int64_t v;
} int64_unaligned_t;
typedef struct SPICE_ATTR_PACKED {
    uint64_t v;
} uint64_unaligned_t;
#include <spice/end-packed.h>

#define read_int8(ptr) (*((int8_t *)(ptr)))
#define write_int8(ptr, val) *(int8_t *)(ptr) = val
#define read_uint8(ptr) (*((uint8_t *)(ptr)))
#define write_uint8(ptr, val) *(uint8_t *)(ptr) = val

#ifdef WORDS_BIGENDIAN
#define read_int16(ptr) ((int16_t)SPICE_BYTESWAP16(((uint16_unaligned_t *)(ptr))->v))
#define write_int16(ptr, val) ((uint16_unaligned_t *)(ptr))->v = SPICE_BYTESWAP16((uint16_t)val)
#define read_uint16(ptr) ((uint16_t)SPICE_BYTESWAP16(((uint16_unaligned_t *)(ptr))->v))
#define write_uint16(ptr, val) ((uint16_unaligned_t *)(ptr))->v = SPICE_BYTESWAP16((uint16_t)val)
#define read_int32(ptr) ((int32_t)SPICE_BYTESWAP32(((uint32_unaligned_t *)(ptr))->v))
#define write_int32(ptr, val) ((uint32_unaligned_t *)(ptr))->v = SPICE_BYTESWAP32((uint32_t)val)
#define read_uint32(ptr) ((uint32_t)SPICE_BYTESWAP32(((uint32_unaligned_t *)(ptr))->v))
#define write_uint32(ptr, val) ((uint32_unaligned_t *)(ptr))->v = SPICE_BYTESWAP32((uint32_t)val)
#define read_int64(ptr) ((int64_t)SPICE_BYTESWAP64(((uint64_unaligned_t *)(ptr))->v))
#define write_int64(ptr, val) ((uint64_unaligned_t *)(ptr))->v = SPICE_BYTESWAP64((uint64_t)val)
#define read_uint64(ptr) ((uint64_t)SPICE_BYTESWAP64(((uint64_unaligned_t *)(ptr))->v))
#define write_uint64(ptr, val) ((uint64_unaligned_t *)(ptr))->v = SPICE_BYTESWAP64((uint64_t)val)
#else
#define read_int16(ptr) (((int16_unaligned_t *)(ptr))->v)
#define write_int16(ptr, val) (((int16_unaligned_t *)(ptr))->v) = val
#define read_uint16(ptr) (((uint16_unaligned_t *)(ptr))->v)
#define write_uint16(ptr, val) (((uint16_unaligned_t *)(ptr))->v) = val
#define read_int32(ptr) (((int32_unaligned_t *)(ptr))->v)
#define write_int32(ptr, val) (((int32_unaligned_t *)(ptr))->v) = val
#define read_uint32(ptr) (((uint32_unaligned_t *)(ptr))->v)
#define write_uint32(ptr, val) (((uint32_unaligned_t *)(ptr))->v) = val
#define read_int64(ptr) (((int64_unaligned_t *)(ptr))->v)
#define write_int64(ptr, val) (((int64_unaligned_t *)(ptr))->v) = val
#define read_uint64(ptr) (((uint64_unaligned_t *)(ptr))->v)
#define write_uint64(ptr, val) (((uint64_unaligned_t *)(ptr))->v) = val
#endif

static int8_t SPICE_GNUC_UNUSED consume_int8(uint8_t **ptr)
{
    int8_t val;
    val = read_int8(*ptr);
    *ptr += 1;
    return val;
}

static uint8_t SPICE_GNUC_UNUSED consume_uint8(uint8_t **ptr)
{
    uint8_t val;
    val = read_uint8(*ptr);
    *ptr += 1;
    return val;
}

static int16_t SPICE_GNUC_UNUSED consume_int16(uint8_t **ptr)
{
    int16_t val;
    val = read_int16(*ptr);
    *ptr += 2;
    return val;
}

static uint16_t SPICE_GNUC_UNUSED consume_uint16(uint8_t **ptr)
{
    uint16_t val;
    val = read_uint16(*ptr);
    *ptr += 2;
    return val;
}

static int32_t SPICE_GNUC_UNUSED consume_int32(uint8_t **ptr)
{
    int32_t val;
    val = read_int32(*ptr);
    *ptr += 4;
    return val;
}

static uint32_t SPICE_GNUC_UNUSED consume_uint32(uint8_t **ptr)
{
    uint32_t val;
    val = read_uint32(*ptr);
    *ptr += 4;
    return val;
}

static int64_t SPICE_GNUC_UNUSED consume_int64(uint8_t **ptr)
{
    int64_t val;
    val = read_int64(*ptr);
    *ptr += 8;
    return val;
}

static uint64_t SPICE_GNUC_UNUSED consume_uint64(uint8_t **ptr)
{
    uint64_t val;
    val = read_uint64(*ptr);
    *ptr += 8;
    return val;
}
static int SPICE_GNUC_UNUSED consume_fd(uint8_t **ptr SPICE_GNUC_UNUSED)
{
    return -1;
}

typedef struct PointerInfo PointerInfo;
typedef void (*message_destructor_t)(uint8_t *message);
typedef uint8_t * (*parse_func_t)(uint8_t *message_start, uint8_t *message_end, uint8_t *struct_data, PointerInfo *ptr_info, int minor);
typedef uint8_t * (*parse_msg_func_t)(uint8_t *message_start, uint8_t *message_end, int minor, size_t *size_out, message_destructor_t *free_message);
typedef uint8_t * (*spice_parse_channel_func_t)(uint8_t *message_start, uint8_t *message_end, uint16_t message_type, int minor, size_t *size_out, message_destructor_t *free_message);

struct PointerInfo {
    uint64_t offset;
    parse_func_t parse;
    void * *dest;
    uint64_t nelements;
};

static uint8_t * parse_array_uint64(uint8_t *message_start, SPICE_GNUC_UNUSED uint8_t *message_end, uint8_t *struct_data, PointerInfo *this_ptr_info, SPICE_GNUC_UNUSED int minor)
{
    uint8_t *in = message_start + this_ptr_info->offset;
    uint8_t *end;
    uint32_t i;

    end = struct_data;
    for (i = 0; i < this_ptr_info->nelements; i++) {
        *(uint64_t *)end = consume_uint64(&in);
        end += sizeof(uint64_t);
    }
    return end;
}

static uint8_t * parse_msg_main_ShortDataSubMarshall(uint8_t *message_start, uint8_t *message_end, SPICE_GNUC_UNUSED int minor, size_t *size, message_destructor_t *free_message)
{
    SPICE_GNUC_UNUSED uint8_t *pos;
    uint8_t *start = message_start;
    uint8_t *data = NULL;
    uint64_t nw_size;
    uint64_t mem_size;
    uint8_t *in, *end;
    SPICE_GNUC_UNUSED intptr_t ptr_size;
    uint32_t n_ptr=0;
    PointerInfo ptr_info[1];
    uint64_t data__extra_size;
    uint64_t data__array__nelements;
    SpiceMsgMainShortDataSubMarshall *out;
    uint32_t i;

    { /* data */
        uint32_t data__value;
        uint64_t data__array__nw_size;
        uint64_t data__array__mem_size;
        uint32_t data_size__value;
        pos = (start + 5);
        if (SPICE_UNLIKELY(pos + 4 > message_end)) {
            goto error;
        }
        data__value = read_uint32(pos);
        if (SPICE_UNLIKELY(data__value >= (uintptr_t) (message_end - message_start))) {
            goto error;
        }
        pos = start + 1;
        if (SPICE_UNLIKELY(pos + 4 > message_end)) {
            goto error;
        }
        data_size__value = read_uint32(pos);
        data__array__nelements = data_size__value;

        data__array__nw_size = (8) * data__array__nelements;
        data__array__mem_size = sizeof(uint64_t) * data__array__nelements;
        if (SPICE_UNLIKELY(data__value + data__array__nw_size > (uintptr_t) (message_end - message_start))) {
            goto error;
        }
        data__extra_size = data__array__mem_size + /* for alignment */ 3;
    }

    nw_size = 9;
    mem_size = sizeof(SpiceMsgMainShortDataSubMarshall) + data__extra_size;

    /* Check if message fits in reported side */
    if (nw_size > (uintptr_t) (message_end - start)) {
        return NULL;
    }

    /* Validated extents and calculated size */
    data = (uint8_t *)(mem_size > UINT32_MAX ? NULL : malloc(mem_size));
    if (SPICE_UNLIKELY(data == NULL)) {
        goto error;
    }
    end = data + sizeof(SpiceMsgMainShortDataSubMarshall);
    in = start;

    out = (SpiceMsgMainShortDataSubMarshall *)data;

    out->dummy_byte = consume_uint8(&in);
    out->data_size = consume_uint32(&in);
    ptr_info[n_ptr].offset = consume_uint32(&in);
    ptr_info[n_ptr].parse = parse_array_uint64;
    ptr_info[n_ptr].dest = (void **)&out->data;
    ptr_info[n_ptr].nelements = data__array__nelements;
    n_ptr++;

    assert(in <= message_end);

    for (i = 0; i < n_ptr; i++) {
        if (ptr_info[i].offset == 0) {
            *ptr_info[i].dest = NULL;
        } else {
            /* Align to 32 bit */
            end = (uint8_t *)SPICE_ALIGN((size_t)end, 4);
            *ptr_info[i].dest = (void *)end;
            end = ptr_info[i].parse(message_start, message_end, end, &ptr_info[i], minor);
            if (SPICE_UNLIKELY(end == NULL)) {
                goto error;
            }
        }
    }

    assert(end <= data + mem_size);

    *size = end - data;
    *free_message = (message_destructor_t) free;
    return data;

   error:
    free(data);
    return NULL;
}

static uint8_t * parse_msg_main_ArrayMessage(uint8_t *message_start, uint8_t *message_end, SPICE_GNUC_UNUSED int minor, size_t *size, message_destructor_t *free_message)
{
    SPICE_GNUC_UNUSED uint8_t *pos;
    uint8_t *start = message_start;
    uint8_t *data = NULL;
    uint64_t nw_size;
    uint64_t mem_size;
    uint8_t *in, *end;
    uint64_t name__nw_size;
    uint64_t name__nelements;
    SpiceMsgMainArrayMessage *out;

    { /* name */
        name__nelements = message_end - (start + 0);

        name__nw_size = name__nelements;
    }

    nw_size = 0 + name__nw_size;
    mem_size = sizeof(SpiceMsgMainArrayMessage);

    /* Check if message fits in reported side */
    if (nw_size > (uintptr_t) (message_end - start)) {
        return NULL;
    }

    /* Validated extents and calculated size */
    data = (uint8_t *)(mem_size > UINT32_MAX ? NULL : malloc(mem_size));
    if (SPICE_UNLIKELY(data == NULL)) {
        goto error;
    }
    end = data + sizeof(SpiceMsgMainArrayMessage);
    in = start;

    out = (SpiceMsgMainArrayMessage *)data;

    memcpy(out->name, in, name__nelements);
    in += name__nelements;

    assert(in <= message_end);
    assert(end <= data + mem_size);

    *size = end - data;
    *free_message = (message_destructor_t) free;
    return data;

   error:
    free(data);
    return NULL;
}

static uint8_t * parse_TestChannel_msg(uint8_t *message_start, uint8_t *message_end, uint16_t message_type, SPICE_GNUC_UNUSED int minor, size_t *size_out, message_destructor_t *free_message)
{
    static parse_msg_func_t funcs1[2] =  {
        parse_msg_main_ShortDataSubMarshall,
        parse_msg_main_ArrayMessage
    };
    if (message_type >= 1 && message_type < 3) {
        return funcs1[message_type-1](message_start, message_end, minor, size_out, free_message);
    }
    return NULL;
}

spice_parse_channel_func_t spice_get_server_channel_parser(uint32_t channel, unsigned int *max_message_type)
{
    static struct {spice_parse_channel_func_t func; unsigned int max_messages; } channels[2] =  {
        { NULL, 0 },
        { parse_TestChannel_msg, 2}
    };
    if (channel < 2) {
        if (max_message_type != NULL) {
            *max_message_type = channels[channel].max_messages;
        }
        return channels[channel].func;
    }
    return NULL;
}

uint8_t * spice_parse_msg(uint8_t *message_start, uint8_t *message_end, uint32_t channel, uint16_t message_type, SPICE_GNUC_UNUSED int minor, size_t *size_out, message_destructor_t *free_message)
{
    spice_parse_channel_func_t func;
    func = spice_get_server_channel_parser(channel, NULL);
    if (func != NULL) {
        return func(message_start, message_end, message_type, minor, size_out, free_message);
    }
    return NULL;
}
