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

#include <iiimp-data.h>

#include "iiimp-dataP.h"
#include "print-misc.h"


IIIMP_object_descriptor *
iiimp_object_descriptor_new(
    IIIMP_data_s *	data_s,
    IIIMP_card16	category,
    IIIMP_card32	object_size,
    IIIMP_card16	id_pre,
    IIIMP_card16	id_dyn,
    IIIMP_string *	rdun,
    IIIMP_string *	hrn,
    IIIMP_string *	signature,
    IIIMP_string *	user)
{
    IIIMP_object_descriptor *	od;

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

    od->nbyte = (2 + 2 + 4 + 2 + 2);
    if (NULL == rdun) {
	od->nbyte += 4;
    } else {
	od->nbyte += rdun->nbyte;
    }
    if (NULL == hrn) {
	od->nbyte += 4;
    } else {
	od->nbyte += hrn->nbyte;
    }
    if (NULL == signature) {
	od->nbyte += 4;
    } else {
	od->nbyte += signature->nbyte;
    }
    if (NULL == user) {
	od->nbyte += 4;
    } else {
	od->nbyte += user->nbyte;
    }

    od->category = category;
    od->size = object_size;
    od->id_pre = id_pre;
    od->id_dyn = id_dyn;
    od->rdun = rdun;
    od->hrn = hrn;
    od->signature = signature;
    od->user = user;
    od->next = NULL;

    return od;
}


void
iiimp_object_descriptor_delete(
    IIIMP_data_s *		data_s,
    IIIMP_object_descriptor *	od)
{
    if (NULL == od) return;
    iiimp_string_delete(data_s, od->rdun);
    iiimp_string_delete(data_s, od->hrn);
    iiimp_string_delete(data_s, od->signature);
    iiimp_string_delete(data_s, od->user);
    free(od);
    return;
}


void
iiimp_object_descriptor_list_delete(
    IIIMP_data_s *		data_s,
    IIIMP_object_descriptor *	od)
{
    IIIMP_object_descriptor *	od_next;
    for (; NULL != od; od = od_next) {
	od_next = od->next;
	iiimp_object_descriptor_delete(data_s, od);
    }
    return;
}


void
iiimp_object_descriptor_pack(
    IIIMP_data_s *		data_s,
    IIIMP_object_descriptor *	m,
    size_t *			nbyte,
    uchar_t **			ptr)
{
    size_t	rest;
    uchar_t *	p;

    rest = *nbyte;
    p = *ptr;

    PUTU16(m->category, rest, p, data_s->byte_swap);
    PUTU16(0, rest, p, data_s->byte_swap);
    PUTU32(m->size, rest, p, data_s->byte_swap);
    PUTU16(m->id_pre, rest, p, data_s->byte_swap);
    PUTU16(m->id_dyn, rest, p, data_s->byte_swap);
    iiimp_string_pack(data_s, m->rdun, &rest, &p);
    iiimp_string_pack(data_s, m->hrn, &rest, &p);
    iiimp_string_pack(data_s, m->signature, &rest, &p);
    iiimp_string_pack(data_s, m->user, &rest, &p);

    *nbyte = rest;
    *ptr = p;

    return;
}


void
iiimp_object_descriptor_list_pack(
    IIIMP_data_s *		data_s,
    IIIMP_object_descriptor *	m,
    size_t *			nbyte,
    uchar_t **			ptr)
{
    size_t	rest;
    uchar_t *	p;

    rest = *nbyte;
    p = *ptr;

    for (; NULL != m; m = m->next) {
	iiimp_object_descriptor_pack(data_s, m, &rest, &p);
    }

    *nbyte = rest;
    *ptr = p;

    return;
}


IIIMP_object_descriptor *
iiimp_object_descriptor_unpack(
    IIIMP_data_s *	data_s,
    size_t *		nbyte,
    const uchar_t **	ptr,
    size_t		nbyte_max)
{
    IIIMP_object_descriptor *	od;
    size_t			rest;
    const uchar_t *		p;

    rest = nbyte_max;
    p = *ptr;

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

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

    GETU16(od->category, rest, p, data_s->byte_swap);
    SKIP16(rest, p);
    GETU32(od->size, rest, p, data_s->byte_swap);
    GETU16(od->id_pre, rest, p, data_s->byte_swap);
    GETU16(od->id_dyn, rest, p, data_s->byte_swap);
    if (od->id_dyn >= (1 << 15)) {
	iiimp_attribute_id_update(data_s, od->id_pre, od->id_dyn);
    }

    od->rdun = NULL;
    od->hrn = NULL;
    od->signature = NULL;
    od->user = NULL;
    od->next = NULL;

    od->rdun = iiimp_string_unpack(data_s, &rest, &p, rest);
    if (NULL == od->rdun) {
	iiimp_object_descriptor_delete(data_s, od);
	return NULL;
    }

    od->hrn = iiimp_string_unpack(data_s, &rest, &p, rest);
    if (NULL == od->hrn) {
	iiimp_object_descriptor_delete(data_s, od);
	return NULL;
    }

    od->signature = iiimp_string_unpack(data_s, &rest, &p, rest);
    if (NULL == od->signature) {
	iiimp_object_descriptor_delete(data_s, od);
	return NULL;
    }

    od->user = iiimp_string_unpack(data_s, &rest, &p, rest);
    if (NULL == od->user) {
	iiimp_object_descriptor_delete(data_s, od);
	return NULL;
    }

    od->nbyte = (2 + 2 + 4 + 2 + 2);
    od->nbyte += od->rdun->nbyte;
    od->nbyte += od->hrn->nbyte;
    od->nbyte += od->signature->nbyte;
    od->nbyte += od->user->nbyte;

    *nbyte = rest;
    *ptr = p;

    return od;
}


IIIMP_object_descriptor *
iiimp_object_descriptor_list_unpack(
    IIIMP_data_s *		data_s,
    size_t *			nbyte,
    const uchar_t **		ptr,
    size_t			nbyte_max)
{
    IIIMP_object_descriptor *	od;
    size_t			rest;
    const uchar_t *		p;
    IIIMP_object_descriptor *	od_first;
    IIIMP_object_descriptor *	od_last;

    rest = nbyte_max;
    p = *ptr;
    od_first = NULL;
    od_last = NULL;

    if (((*nbyte) < nbyte_max) || (0 != (rest & 0x01))) {
	data_s->status = IIIMP_DATA_INVALID;
	return NULL;
    }

    while (0 < rest) {
	od = iiimp_object_descriptor_unpack(data_s, &rest, &p, rest);
	if (NULL == od) {
	    iiimp_object_descriptor_list_delete(data_s, od_first);
	    return NULL;
	} else {
	    if (NULL == od_first) {
		od_first = od;
	    } else {
		od_last->next = od;
	    }
	    od_last = od;
	}
    }

    *nbyte -= (nbyte_max - rest);
    *ptr = p;

    return od_first;
}


void
iiimp_object_descriptor_print(
    IIIMP_data_s *		data_s,
    IIIMP_object_descriptor *	m)
{
    if (NULL == m) return;

    (void)fputc('\t', data_s->print_fp);

    (void)fprintf(data_s->print_fp, "%s (%d)",
		  object_descriptor_category_string_get(m->category),
		  m->category);
    (void)fputc(' ', data_s->print_fp);
    (void)fprintf(data_s->print_fp, "size=%d ", m->size);
    (void)fprintf(data_s->print_fp, "predefined=0x%x ", m->id_pre);
    (void)fprintf(data_s->print_fp, "dynamic=0x%x ", m->id_dyn);
    (void)fputc('\n', data_s->print_fp);

    (void)fprintf(data_s->print_fp, "\tname=");
    iiimp_string_print(data_s, m->rdun);
    (void)fputc('\n', data_s->print_fp);

    (void)fprintf(data_s->print_fp, "\tdescription=");
    iiimp_string_print(data_s, m->hrn);
    (void)fputc('\n', data_s->print_fp);

    (void)fprintf(data_s->print_fp, "\tsignature=");
    iiimp_string_print(data_s, m->signature);
    (void)fputc('\n', data_s->print_fp);

    (void)fprintf(data_s->print_fp, "\tuser=");
    iiimp_string_print(data_s, m->user);
    (void)fputc('\n', data_s->print_fp);
}


void
iiimp_object_descriptor_list_print(
    IIIMP_data_s *		data_s,
    IIIMP_object_descriptor *	m)
{
    for (; NULL != m; m = m->next) {
	iiimp_object_descriptor_print(data_s, m);
    }
}


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