#include <stdlib.h>
#include <string.h>
#include <sys/types.h>

#include <iiimp-data.h>

#include "iiimp-dataP.h"


static IIIMP_annotation_value *
iiimp_annotation_value_new(
    IIIMP_data_s *	data_s,
    IIIMP_int32		start_index,
    IIIMP_int32		end_index,
    IIIMP_text *	ptr_text,
    IIIMP_string *	ptr_str)
{
    IIIMP_annotation_value *	anno_v;

    anno_v = (IIIMP_annotation_value *)malloc(sizeof (IIIMP_annotation_value));
    if (NULL == anno_v) {
	data_s->status = IIIMP_DATA_MALLOC_ERROR;
	return NULL;
    }

    anno_v->nbyte = (4 + 4 + 4);
    anno_v->next = NULL;

    anno_v->start_index = start_index;
    anno_v->end_index = end_index;

    if (NULL != ptr_str) {
	anno_v->length = ptr_str->nbyte;
	anno_v->nbyte += ptr_str->nbyte;
	anno_v->v.string = ptr_str;
    } else if (NULL != ptr_text) {
	anno_v->length = ptr_text->nbyte;
	anno_v->nbyte += ptr_text->nbyte;
	anno_v->v.text = ptr_text;
    } else {
	free(anno_v);
	data_s->status = IIIMP_DATA_INVALID;
	return NULL;
    }

    return anno_v;
}


IIIMP_annotation_value *
iiimp_annotation_value_text_new(
    IIIMP_data_s *	data_s,
    IIIMP_int32		start_index,
    IIIMP_int32		end_index,
    IIIMP_text *	value)
{
    return iiimp_annotation_value_new(data_s, start_index, end_index,
				      value, NULL);
}


void
iiimp_annotation_text_delete(
    IIIMP_data_s *		data_s,
    IIIMP_annotation_value *	anno_v)
{
    IIIMP_annotation_value *	anno_next;
    for (; NULL != anno_v; anno_v = anno_next) {
	anno_next = anno_v->next;
	iiimp_text_delete(data_s, anno_v->v.text);
	free(anno_v);
    }
    return;
}


IIIMP_annotation_value *
iiimp_annotation_value_string_new(
    IIIMP_data_s *	data_s,
    IIIMP_int32		start_index,
    IIIMP_int32		end_index,
    IIIMP_string *	value)
{
    return iiimp_annotation_value_new(data_s, start_index, end_index,
				      NULL, value);
}


void
iiimp_annotation_string_delete(
    IIIMP_data_s *		data_s,
    IIIMP_annotation_value *	anno_v)
{
    IIIMP_annotation_value *	anno_next;

    for (; NULL != anno_v; anno_v = anno_next) {
	anno_next = anno_v->next;
	iiimp_string_list_delete(data_s, anno_v->v.string);
	free(anno_v);
    }

    return;
}


void
iiimp_annotation_text_pack(
    IIIMP_data_s *		data_s,
    IIIMP_annotation_value *	m,
    size_t *			nbyte,
    uchar_t **			ptr)
{
    size_t			rest;
    uchar_t *			p;
    IIIMP_annotation_value *	v;
    size_t			length;

    rest = *nbyte;
    p = *ptr;

    length = 0;
    for (v = m; NULL != v; v = v->next) {
	length += (4 + 4 + 4 + v->v.text->nbyte);
    }
    PUTU32(length, rest, p, data_s->byte_swap);

    for (; NULL != m; m = m->next) {
	PUT32(m->start_index, rest, p, data_s->byte_swap);
	PUT32(m->end_index, rest, p, data_s->byte_swap);
	PUT32(m->length, rest, p, data_s->byte_swap);
	iiimp_text_pack(data_s, m->v.text, &rest, &p);
    }

    *nbyte = rest;
    *ptr = p;

    return;
}


void
iiimp_annotation_string_pack(
    IIIMP_data_s *		data_s,
    IIIMP_annotation_value *	m,
    size_t *			nbyte,
    uchar_t **			ptr)
{
    size_t			rest;
    uchar_t *			p;
    IIIMP_annotation_value *	v;
    size_t			length;

    rest = *nbyte;
    p = *ptr;

    length = 0;
    for (v = m; NULL != v; v = v->next) {
	length += (4 + 4 + 4 + v->v.string->nbyte);
    }
    PUTU32(length, rest, p, data_s->byte_swap);

    for (; NULL != m; m = m->next) {
	PUT32(m->start_index, rest, p, data_s->byte_swap);
	PUT32(m->end_index, rest, p, data_s->byte_swap);
	PUT32(m->length, rest, p, data_s->byte_swap);
	iiimp_string_pack(data_s, m->v.string, &rest, &p);
    }

    *nbyte = rest;
    *ptr = p;

    return;
}


IIIMP_annotation_value *
iiimp_annotation_text_unpack(
    IIIMP_data_s *	data_s,
    size_t *		nbyte,
    const uchar_t **	ptr,
    size_t		nbyte_max)
{
    IIIMP_annotation_value *	anno_v;
    size_t			rest;
    const uchar_t *		p;
    IIIMP_annotation_value *	anno_v_first;
    IIIMP_annotation_value *	anno_v_last = NULL;

    rest = nbyte_max;
    p = *ptr;

    anno_v_first = NULL;
    while (0 < rest) {
	if ((*nbyte < rest) || (rest < (4 + 4 + 4))) {
	    iiimp_annotation_text_delete(data_s, anno_v_first);
	    data_s->status = IIIMP_DATA_INVALID;
	    return NULL;
	}

	anno_v = (IIIMP_annotation_value *)
	    malloc(sizeof (IIIMP_annotation_value));
	if (NULL == anno_v) {
	    iiimp_annotation_text_delete(data_s, anno_v_first);
	    data_s->status = IIIMP_DATA_MALLOC_ERROR;
	    return NULL;
	}

	anno_v->next = NULL;
	GET32(anno_v->start_index, rest, p, data_s->byte_swap);
	GET32(anno_v->end_index, rest, p, data_s->byte_swap);
	GET32(anno_v->length, rest, p, data_s->byte_swap);
	if (anno_v->length < rest) {
	    iiimp_annotation_text_delete(data_s, anno_v_first);
	    data_s->status = IIIMP_DATA_INVALID;
	    return NULL;
	}
	anno_v->v.text = iiimp_text_unpack(data_s, &rest, &p, anno_v->length);
	if (NULL == anno_v->v.text) {
	    iiimp_annotation_text_delete(data_s, anno_v_first);
	    return NULL;
	}

	if (NULL == anno_v_first) {
	    anno_v_first = anno_v;
	    anno_v_last = anno_v;
	} else {
	    anno_v_last->next = anno_v;
	    anno_v_last = anno_v;
	}
    }

    *nbyte = rest;
    *ptr = p;

    return anno_v_first;
}


IIIMP_annotation_value *
iiimp_annotation_string_unpack(
    IIIMP_data_s *	data_s,
    size_t *		nbyte,
    const uchar_t **	ptr,
    size_t		nbyte_max)
{
    IIIMP_annotation_value *	anno_v;
    size_t			rest;
    const uchar_t *		p;
    IIIMP_annotation_value *	anno_v_first;
    IIIMP_annotation_value *	anno_v_last = NULL;

    rest = nbyte_max;
    p = *ptr;

    anno_v_first = NULL;
    while (0 < rest) {
	if (rest < (4 + 4 + 4)) {
	    data_s->status = IIIMP_DATA_INVALID;
	    return NULL;
	}
	anno_v = (IIIMP_annotation_value *)
	    malloc(sizeof (IIIMP_annotation_value));
	if (NULL == anno_v) {
	    iiimp_annotation_string_delete(data_s, anno_v_first);
	    data_s->status = IIIMP_DATA_MALLOC_ERROR;
	    return NULL;
	}

	anno_v->next = NULL;
	GET32(anno_v->start_index, rest, p, data_s->byte_swap);
	GET32(anno_v->end_index, rest, p, data_s->byte_swap);
	GET32(anno_v->length, rest, p, data_s->byte_swap);
	if (anno_v->length < rest) {
	    iiimp_annotation_string_delete(data_s, anno_v_first);
	    data_s->status = IIIMP_DATA_INVALID;
	    return NULL;
	}
	anno_v->v.string = iiimp_string_unpack(data_s, &rest, &p,
					       anno_v->length);
	if (NULL == anno_v->v.string) {
	    iiimp_annotation_string_delete(data_s, anno_v_first);
	    return NULL;
	}
	if (NULL == anno_v_first) {
	    anno_v_first = anno_v;
	    anno_v_last = anno_v;
	} else {
	    anno_v_last->next = anno_v;
	    anno_v_last = anno_v;
	}
    }

    *nbyte = rest;
    *ptr = p;

    return anno_v_first;
}


/* Local Variables: */
/* c-file-style: "iiim-project" */
/* End: */
