#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>

#include "../../../src/util/memory.h"
#include "../../../src/util/error.h"
#include "../../../src/dis/dis/xdr_dis.h"
#include "../../../src/dis/dis/datum.h"
#include "../../../src/dis/dis/xdr.h"

#define IS_LITTLE_ENDIAN (((char *)&(int){1})[0] == 1)

static int err;

static void fill(void *block, int block_len)
{
	unsigned char *p = block;
	unsigned char b = 1;
	
	while(block_len > 0){
		*p = b;
		b++;
		if( b == 0 )
			b = 1;
		p++;
		block_len--;
	}
}


static void printbuf(char *b, int blen)
{
	int i;
	
	for(i = 0; i < blen; i++){
		if( i != 0 && i % 16 == 0 )
			printf("\n");
		printf(" 0x%02x", b[i]&255);
	}
}


static int findDiffOffset(char *a, int alen, char *b, int blen)
{
	int i;
	for(i = 0; i < alen && i < blen; i++)
		if( a[i] != b[i] )
			return i;
	return i;
}


static void cmp(int line, void *got, int gotlen, void *exp, int explen)
{
	if( gotlen == explen && memcmp(got, exp, explen) == 0 )
		return;
	
	int offset = findDiffOffset((char *) got, gotlen, (char *) exp, explen);
	
	printf("test failed in line %d at byte offset %d:", line, offset);
	printf("\n    got: ");  printbuf(got, gotlen);
	printf("\n    exp: ");  printbuf(exp, explen);
	printf("\n");
	err++;
}


static void test_dis_entity_state_pdu()
{
	char      buf[2000];
	xdr_Type *xdr;
	int       buf_len_in, buf_len_out;
	dis_entity_state_pdu es_in, es_out;
	//dis_articulation_parm ap_in, ap_out;
	
	fill(&es_in, sizeof(es_in));
	es_in.hdr.protocol_version = DISProtocolVersionIEEE1278_95;
	es_in.hdr.pdu_type = PDUTypeEntityState;
	es_in.hdr.protocol_family = PDUFamilyEntityInformation;
	es_in.hdr.length = 0; // set below
	es_in.hdr.padding = 0;
	// xdr_dis_articulation_parm() not implemented.
	es_in.art_parm_count = 0;
	es_in.art_parm = NULL;
	xdr = xdr_new(buf, sizeof(buf), xdr_ENCODE);
	assert( xdr_dis_pdu(xdr, (dis_pdu *) &es_in) );
	buf_len_in = xdr_getpos(xdr);
	xdr_free(xdr);
/*
 *  Now for a hack. We need to insert the correct packet length into
 *  the PDU header.  The header is somewhat stable from one protocol release
 *  to the next, so I've just hard-coded it here.
 */

	es_in.hdr.length = buf_len_in;
	*((u_short *) &buf[8]) = htons(buf_len_in);
	
	//printf("generated buf:\n");  printbuf(buf, buf_len_in);  printf("\n");
	
	if( IS_LITTLE_ENDIAN ){ // sorry, only little endian cpu here
		// Compares the generated packet with the expected one:
		char *exp_buf = 
		"\x05\x02\x01\x01\x08\x07\x06\x05\x00\x90\x00\x00\x0e\x0d\x10\x0f"
		"\x12\x11\x13\x00\x15\x16\x18\x17\x19\x1a\x1b\x1c\x1d\x1e\x20\x1f"
		"\x21\x22\x23\x24\x28\x27\x26\x25\x2c\x2b\x2a\x29\x30\x2f\x2e\x2d"
		"\x38\x37\x36\x35\x34\x33\x32\x31\x40\x3f\x3e\x3d\x3c\x3b\x3a\x39"
		"\x48\x47\x46\x45\x44\x43\x42\x41\x4c\x4b\x4a\x49\x50\x4f\x4e\x4d"
		"\x54\x53\x52\x51\x58\x57\x56\x55\x59\x5a\x5b\x5c\x5d\x5e\x5f\x60"
		"\x61\x62\x63\x64\x65\x66\x67\x68\x6c\x6b\x6a\x69\x70\x6f\x6e\x6d"
		"\x74\x73\x72\x71\x78\x77\x76\x75\x7c\x7b\x7a\x79\x80\x7f\x7e\x7d"
		"\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x90\x8f\x8e\x8d";
		int exp_buf_len = 9*16;
		cmp(__LINE__, buf, buf_len_in, exp_buf, exp_buf_len);
	}
	
	// Decodes the generated packet:
	memory_zero(&es_out);
	xdr = xdr_new(buf, buf_len_in, xdr_DECODE);
	assert( xdr_dis_pdu(xdr, (dis_pdu *) &es_out) );
	buf_len_out = xdr_getpos(xdr);
	xdr_free(xdr);
	
	// Compares the decoded data with the original data:
	assert(buf_len_out == buf_len_in);
	cmp(__LINE__, &es_out.hdr, sizeof(es_out.hdr), &es_in.hdr, sizeof(es_in.hdr));
	cmp(__LINE__, &es_out.id, sizeof(es_out.id), &es_in.id, sizeof(es_in.id));
	cmp(__LINE__, &es_out.type, sizeof(es_out.type), &es_in.type, sizeof(es_in.type));
	cmp(__LINE__, &es_out.alt_type, sizeof(es_out.alt_type), &es_in.alt_type, sizeof(es_in.alt_type));
	cmp(__LINE__, &es_out.vel, sizeof(es_out.vel), &es_in.vel, sizeof(es_in.vel));
	cmp(__LINE__, &es_out.pos, sizeof(es_out.pos), &es_in.pos, sizeof(es_in.pos));
	cmp(__LINE__, &es_out.orientation, sizeof(es_out.orientation), &es_in.orientation, sizeof(es_in.orientation));
	cmp(__LINE__, &es_out.appearance, sizeof(es_out.appearance), &es_in.appearance, sizeof(es_in.appearance));
	cmp(__LINE__, &es_out.dr_parm, sizeof(es_out.dr_parm), &es_in.dr_parm, sizeof(es_in.dr_parm));
	cmp(__LINE__, &es_out.marking, sizeof(es_out.marking), &es_in.marking, sizeof(es_in.marking));
	cmp(__LINE__, &es_out.capabilities, sizeof(es_out.capabilities), &es_in.capabilities, sizeof(es_in.capabilities));
	cmp(__LINE__, &es_out.art_parm, sizeof(es_out.art_parm), &es_in.art_parm, sizeof(es_in.art_parm));
	dis_freePDUComponents((dis_pdu *) &es_out);
}


static void test_dis_fire_pdu()
{
	char      buf[2000];
	xdr_Type *xdr;
	int       buf_len_in, buf_len_out;
	dis_fire_pdu fire_in, fire_out;
	
	fill(&fire_in, sizeof(fire_in));
	fire_in.hdr.protocol_version = DISProtocolVersionIEEE1278_95;
	fire_in.hdr.pdu_type = PDUTypeFire; // pkt offset 2
	fire_in.hdr.protocol_family = PDUFamilyWarfare; // pkt offset 3
	fire_in.hdr.length = 0; // set below
	fire_in.hdr.padding = 0;
	xdr = xdr_new(buf, sizeof(buf), xdr_ENCODE);
	assert( xdr_dis_pdu(xdr, (dis_pdu *) &fire_in) );
	buf_len_in = xdr_getpos(xdr);
	xdr_free(xdr);
/*
 *  Now for a hack. We need to insert the correct packet length into
 *  the PDU header.  The header is somewhat stable from one protocol release
 *  to the next, so I've just hard-coded it here.
 */

	fire_in.hdr.length = buf_len_in;
	*((u_short *) &buf[8]) = htons(buf_len_in);
	
	//printf("generated buf:\n");  printbuf(buf, buf_len_in);  printf("\n");
	
	if( IS_LITTLE_ENDIAN ){ // sorry, only little endian cpu here
		// Compares the generated packet with the expected one:
		char *exp_buf = 
		"\x05\x02\x02\x02\x08\x07\x06\x05\x00\x60\x00\x00\x0e\x0d\x10\x0f"
		"\x12\x11\x14\x13\x16\x15\x18\x17\x1a\x19\x1c\x1b\x1e\x1d\x20\x1f"
		"\x22\x21\x24\x23\x28\x27\x26\x25\x30\x2f\x2e\x2d\x2c\x2b\x2a\x29"
		"\x38\x37\x36\x35\x34\x33\x32\x31\x40\x3f\x3e\x3d\x3c\x3b\x3a\x39"
		"\x41\x42\x44\x43\x45\x46\x47\x48\x4a\x49\x4c\x4b\x4e\x4d\x50\x4f"
		"\x54\x53\x52\x51\x58\x57\x56\x55\x5c\x5b\x5a\x59\x60\x5f\x5e\x5d";
		int exp_buf_len = 6*16;
		cmp(__LINE__, buf, buf_len_in, exp_buf, exp_buf_len);
	}
	
	// Decodes the generated packet:
	memory_zero(&fire_out);
	xdr = xdr_new(buf, buf_len_in, xdr_DECODE);
	assert( xdr_dis_pdu(xdr, (dis_pdu *) &fire_out) );
	buf_len_out = xdr_getpos(xdr);
	xdr_free(xdr);
	
	// Compares the decoded data with the original data:
	assert(buf_len_out == buf_len_in);
	cmp(__LINE__, &fire_out.hdr, sizeof(fire_out.hdr), &fire_in.hdr, sizeof(fire_in.hdr));
	cmp(__LINE__, &fire_out.firing_id, sizeof(fire_out.firing_id), &fire_in.firing_id, sizeof(fire_in.firing_id));
	cmp(__LINE__, &fire_out.target_id, sizeof(fire_out.target_id), &fire_in.target_id, sizeof(fire_in.target_id));
	cmp(__LINE__, &fire_out.munition_id, sizeof(fire_out.munition_id), &fire_in.munition_id, sizeof(fire_in.munition_id));
	cmp(__LINE__, &fire_out.event, sizeof(fire_out.event), &fire_in.event, sizeof(fire_in.event));
	cmp(__LINE__, &fire_out.fire_mission_index, sizeof(fire_out.fire_mission_index), &fire_in.fire_mission_index, sizeof(fire_in.fire_mission_index));
	cmp(__LINE__, &fire_out.burst, sizeof(fire_out.burst), &fire_in.burst, sizeof(fire_in.burst));
	cmp(__LINE__, &fire_out.vel, sizeof(fire_out.vel), &fire_in.vel, sizeof(fire_in.vel));
	cmp(__LINE__, &fire_out.range, sizeof(fire_out.range), &fire_in.range, sizeof(fire_in.range));
	dis_freePDUComponents((dis_pdu *) &fire_out);
}


static void test_dis_detonation_pdu()
{
	char      buf[2000];
	xdr_Type *xdr;
	int       buf_len_in, buf_len_out;
	dis_detonation_pdu det_in, det_out;
	
	fill(&det_in, sizeof(det_in));
	det_in.hdr.protocol_version = DISProtocolVersionIEEE1278_95;
	det_in.hdr.pdu_type = PDUTypeDetonation; // pkt offset 2
	det_in.hdr.protocol_family = PDUFamilyWarfare; // pkt offset 3
	det_in.hdr.length = 0; // set below
	det_in.hdr.padding = 0;
	det_in.num_art_parms = 0;
	det_in.art_parm = NULL;
	xdr = xdr_new(buf, sizeof(buf), xdr_ENCODE);
	assert( xdr_dis_pdu(xdr, (dis_pdu *) &det_in) );
	buf_len_in = xdr_getpos(xdr);
	xdr_free(xdr);
/*
 *  Now for a hack. We need to insert the correct packet length into
 *  the PDU header.  The header is somewhat stable from one protocol release
 *  to the next, so I've just hard-coded it here.
 */

	det_in.hdr.length = buf_len_in;
	*((u_short *) &buf[8]) = htons(buf_len_in);
	
	//printf("generated buf:\n");  printbuf(buf, buf_len_in);  printf("\n");
	
	if( IS_LITTLE_ENDIAN ){ // sorry, only little endian cpu here
		// Compares the generated packet with the expected one:
		char *exp_buf = 
		"\x05\x02\x03\x02\x08\x07\x06\x05\x00\x68\x00\x00\x0e\x0d\x10\x0f"
		"\x12\x11\x14\x13\x16\x15\x18\x17\x1a\x19\x1c\x1b\x1e\x1d\x20\x1f"
		"\x22\x21\x24\x23\x28\x27\x26\x25\x2c\x2b\x2a\x29\x30\x2f\x2e\x2d"
		"\x38\x37\x36\x35\x34\x33\x32\x31\x40\x3f\x3e\x3d\x3c\x3b\x3a\x39"
		"\x48\x47\x46\x45\x44\x43\x42\x41\x49\x4a\x4c\x4b\x4d\x4e\x4f\x50"
		"\x52\x51\x54\x53\x56\x55\x58\x57\x5c\x5b\x5a\x59\x60\x5f\x5e\x5d"
		"\x64\x63\x62\x61\x65\x00\x68\x67";
		int exp_buf_len = 6*16+8;
		cmp(__LINE__, buf, buf_len_in, exp_buf, exp_buf_len);
	}
	
	// Decodes the generated packet:
	memory_zero(&det_out);
	xdr = xdr_new(buf, buf_len_in, xdr_DECODE);
	assert( xdr_dis_pdu(xdr, (dis_pdu *) &det_out) );
	buf_len_out = xdr_getpos(xdr);
	xdr_free(xdr);
	
	// Compares the decoded data with the original data:
	assert(buf_len_out == buf_len_in);
	cmp(__LINE__, &det_out.hdr, sizeof(det_out.hdr), &det_in.hdr, sizeof(det_in.hdr));
	cmp(__LINE__, &det_out.firing_id, sizeof(det_out.firing_id), &det_in.firing_id, sizeof(det_in.firing_id));
	cmp(__LINE__, &det_out.target_id, sizeof(det_out.target_id), &det_in.target_id, sizeof(det_in.target_id));
	cmp(__LINE__, &det_out.munition_id, sizeof(det_out.munition_id), &det_in.munition_id, sizeof(det_in.munition_id));
	cmp(__LINE__, &det_out.event, sizeof(det_out.event), &det_in.event, sizeof(det_in.event));
	cmp(__LINE__, &det_out.pos, sizeof(det_out.pos), &det_in.pos, sizeof(det_in.pos));
	cmp(__LINE__, &det_out.burst, sizeof(det_out.burst), &det_in.burst, sizeof(det_in.burst));
	cmp(__LINE__, &det_out.loc, sizeof(det_out.loc), &det_in.loc, sizeof(det_in.loc));
	cmp(__LINE__, &det_out.result, sizeof(det_out.result), &det_in.result, sizeof(det_in.result));
	cmp(__LINE__, &det_out.num_art_parms, sizeof(det_out.num_art_parms), &det_in.num_art_parms, sizeof(det_in.num_art_parms));
	cmp(__LINE__, &det_out.pad, sizeof(det_out.pad), &det_in.pad, sizeof(det_in.pad));
	cmp(__LINE__, &det_out.art_parm, sizeof(det_out.art_parm), &det_in.art_parm, sizeof(det_in.art_parm));
	dis_freePDUComponents((dis_pdu *) &det_out);
}


static void test_dis_emission_pdu()
{
	char      buf[2000];
	xdr_Type *xdr;
	int       buf_len_in, buf_len_out;
	dis_em_emission_pdu em_in, em_out;
	dis_track_info tracked_target_in;
	dis_beam_info beam_in;
	dis_em_system_info system_in;
	
	fill(&em_in, sizeof(em_in));
	em_in.hdr.protocol_version = DISProtocolVersionIEEE1278_95;
	em_in.hdr.pdu_type = PDUTypeEmission; // pkt offset 2
	em_in.hdr.protocol_family = PDUFamilyDistributedEmissionRegeneration; // pkt offset 3
	em_in.hdr.length = 0; // set below
	em_in.hdr.padding = 0;
	
	fill(&tracked_target_in, sizeof(tracked_target_in));
	
	fill(&beam_in, sizeof(beam_in));
	beam_in.num_targets = 1;
	beam_in.tracked_target = &tracked_target_in;
	
	fill(&system_in, sizeof(system_in));
	system_in.num_beams = 1;
	system_in.beam = &beam_in;
	em_in.num_systems = 1;
	em_in.system = &system_in;
	
	dis_addPDUSizes((dis_pdu *) &em_in);
	
	xdr = xdr_new(buf, sizeof(buf), xdr_ENCODE);
	assert( xdr_dis_pdu(xdr, (dis_pdu *) &em_in) );
	buf_len_in = xdr_getpos(xdr);
	xdr_free(xdr);
/*
 *  Now for a hack. We need to insert the correct packet length into
 *  the PDU header.  The header is somewhat stable from one protocol release
 *  to the next, so I've just hard-coded it here.
 */

	em_in.hdr.length = buf_len_in;
	*((u_short *) &buf[8]) = htons(buf_len_in);
	
	//printf("generated buf:\n");  printbuf(buf, buf_len_in);  printf("\n");
	
	if( IS_LITTLE_ENDIAN ){ // sorry, only little endian cpu here
		// Compares the generated packet with the expected one:
		char *exp_buf = 
		"\x05\x02\x17\x06\x08\x07\x06\x05\x00\x6c\x00\x00\x0e\x0d\x10\x0f"
		"\x12\x11\x14\x13\x16\x15\x18\x17\x19\x01\x1c\x1b\x14\x01\x04\x03"
		"\x06\x05\x07\x08\x0c\x0b\x0a\x09\x10\x0f\x0e\x0d\x14\x13\x12\x11"
		"\x0f\x02\x04\x03\x08\x07\x06\x05\x0c\x0b\x0a\x09\x10\x0f\x0e\x0d"
		"\x14\x13\x12\x11\x18\x17\x16\x15\x1c\x1b\x1a\x19\x20\x1f\x1e\x1d"
		"\x24\x23\x22\x21\x28\x27\x26\x25\x2c\x2b\x2a\x29\x2d\x01\x2f\x30"
		"\x34\x33\x32\x31\x02\x01\x04\x03\x06\x05\x07\x08";
		int exp_buf_len = 6*16+12;
		cmp(__LINE__, buf, buf_len_in, exp_buf, exp_buf_len);
	}
	
	// Decodes the generated packet:
	memory_zero(&em_out);
	xdr = xdr_new(buf, buf_len_in, xdr_DECODE);
	assert( xdr_dis_pdu(xdr, (dis_pdu *) &em_out) );
	buf_len_out = xdr_getpos(xdr);
	xdr_free(xdr);
	
	// Compares the decoded data with the original data:
	assert(buf_len_out == buf_len_in);
	cmp(__LINE__, &em_out.hdr, sizeof(em_out.hdr), &em_in.hdr, sizeof(em_in.hdr));
	cmp(__LINE__, &em_out.emitter_id, sizeof(em_out.emitter_id), &em_in.emitter_id, sizeof(em_in.emitter_id));
	cmp(__LINE__, &em_out.event, sizeof(em_out.event), &em_in.event, sizeof(em_in.event));
	cmp(__LINE__, &em_out.state_update, sizeof(em_out.state_update), &em_in.state_update, sizeof(em_in.state_update));
	cmp(__LINE__, &em_out.num_systems, sizeof(em_out.num_systems), &em_in.num_systems, sizeof(em_in.num_systems));
	//cmp(__LINE__, &em_out.pad, sizeof(em_out.pad), &em_in.pad, sizeof(em_in.pad));
	cmp(__LINE__, &em_out.system[0].sys_data_length, sizeof(em_out.system[0].sys_data_length), &em_in.system[0].sys_data_length, sizeof(em_in.system[0].sys_data_length));
	cmp(__LINE__, &em_out.system[0].num_beams, sizeof(em_out.system[0].num_beams), &em_in.system[0].num_beams, sizeof(em_in.system[0].num_beams));
	cmp(__LINE__, &em_out.system[0].emitter_system, sizeof(em_out.system[0].emitter_system), &em_in.system[0].emitter_system, sizeof(em_in.system[0].emitter_system));
	cmp(__LINE__, &em_out.system[0].location, sizeof(em_out.system[0].location), &em_in.system[0].location, sizeof(em_in.system[0].location));
	dis_beam_info *beam_out = &em_out.system[0].beam[0];
	cmp(__LINE__, &beam_out->beam_data_length, sizeof(beam_out->beam_data_length), &beam_out->beam_data_length, sizeof(beam_out->beam_data_length));
	cmp(__LINE__, &beam_out->beam_id, sizeof(beam_out->beam_id), &beam_out->beam_id, sizeof(beam_out->beam_id));
	cmp(__LINE__, &beam_out->beam_parm_index, sizeof(beam_out->beam_parm_index), &beam_out->beam_parm_index, sizeof(beam_out->beam_parm_index));
	cmp(__LINE__, &beam_out->fundamental, sizeof(beam_out->fundamental), &beam_out->fundamental, sizeof(beam_out->fundamental));
	cmp(__LINE__, &beam_out->beam_function, sizeof(beam_out->beam_function), &beam_out->beam_function, sizeof(beam_out->beam_function));
	cmp(__LINE__, &beam_out->num_targets, sizeof(beam_out->num_targets), &beam_out->num_targets, sizeof(beam_out->num_targets));
	cmp(__LINE__, &beam_out->high_density_track_jam, sizeof(beam_out->high_density_track_jam), &beam_out->high_density_track_jam, sizeof(beam_out->high_density_track_jam));
	cmp(__LINE__, &beam_out->jamming_mode, sizeof(beam_out->jamming_mode), &beam_out->jamming_mode, sizeof(beam_out->jamming_mode));
	dis_track_info *tracked_target_out = &beam_out->tracked_target[0];
	cmp(__LINE__, &tracked_target_out->target, sizeof(tracked_target_out->target), &tracked_target_out->target, sizeof(tracked_target_out->target));
	cmp(__LINE__, &tracked_target_out->emitter_id, sizeof(tracked_target_out->emitter_id), &tracked_target_out->emitter_id, sizeof(tracked_target_out->emitter_id));
	cmp(__LINE__, &tracked_target_out->beam_id, sizeof(tracked_target_out->beam_id), &tracked_target_out->beam_id, sizeof(tracked_target_out->beam_id));
	dis_freePDUComponents((dis_pdu *) &em_out);
}


static void test_dis_set_data_pdu()
{
	xdr_Type *xdr;
	char      buf[2000];
	int       buf_len_in, buf_len_out;
	dis_set_data_pdu sd_in, sd_out;
	dis_fixed_datum fixed_datum_in;
	dis_variable_datum variable_datum_in;
	
	fill(&sd_in, sizeof(sd_in));
	sd_in.hdr.protocol_version = DISProtocolVersionIEEE1278_95;
	sd_in.hdr.pdu_type = PDUTypeSetData; // pkt offset 2
	sd_in.hdr.protocol_family = PDUFamilySimulationManagement; // pkt offset 3
	sd_in.hdr.length = 0; // set below
	sd_in.hdr.padding = 0;
	
	fill(&fixed_datum_in, sizeof(fixed_datum_in));
	fill(&variable_datum_in, sizeof(variable_datum_in));
	variable_datum_in.datum_id = datum_Name;
	/*
	 * "The length field shall specify the length of the variable datum in bits.
	 * The field of Variable Datum Value shall be padded at the end to make the
	 * length a multiple of 64-bits."
	 */
	char *s = "AAAAAA";
	
	variable_datum_in.value.ptr_value = (unsigned char *) s;
	variable_datum_in.value_length = 8*strlen(s);
	
	sd_in.datum_info.num_fixed_data = 1;
	sd_in.datum_info.num_variable_data = 1;
	sd_in.datum_info.fixed_datum = &fixed_datum_in;
	sd_in.datum_info.variable_datum = &variable_datum_in;
	
	xdr = xdr_new(buf, sizeof(buf), xdr_ENCODE);
	assert( xdr_dis_pdu(xdr, (dis_pdu *) &sd_in) );
	buf_len_in = xdr_getpos(xdr);
	xdr_free(xdr);
/*
 *  Now for a hack. We need to insert the correct packet length into
 *  the PDU header.  The header is somewhat stable from one protocol release
 *  to the next, so I've just hard-coded it here.
 */

	sd_in.hdr.length = buf_len_in;
	*((u_short *) &buf[8]) = htons(buf_len_in);
	
	if( IS_LITTLE_ENDIAN ){ // sorry, only little endian cpu here
		// Compares the generated packet with the expected one:
		char *exp_buf = 
		"\x05\x02\x13\x05\x08\x07\x06\x05\x00\x3c\x00\x00\x0e\x0d\x10\x0f"
		"\x12\x11\x14\x13\x16\x15\x18\x17\x1c\x1b\x1a\x19\x00\x00\x00\x01"
		"\x00\x00\x00\x01\x04\x03\x02\x01\x08\x07\x06\x05\x00\x00\xa8\x5c"
		"\x00\x00\x00\x30\x41\x41\x41\x41\x41\x41\x00\x00";
		int exp_buf_len = 3*16+12;
		cmp(__LINE__, buf, buf_len_in, exp_buf, exp_buf_len);
	}
	
	// Decodes the generated packet:
	memory_zero(&sd_out);
	xdr = xdr_new(buf, buf_len_in, xdr_DECODE);
	assert( xdr_dis_pdu(xdr, (dis_pdu *) &sd_out) );
	buf_len_out = xdr_getpos(xdr);
	xdr_free(xdr);
	
	// Compares the decoded data with the original data:
	assert(buf_len_out == buf_len_in);
	cmp(__LINE__, &sd_out.hdr, sizeof(sd_out.hdr), &sd_in.hdr, sizeof(sd_in.hdr));
	cmp(__LINE__, &sd_out.orig_id, sizeof(sd_out.orig_id), &sd_in.orig_id, sizeof(sd_in.orig_id));
	cmp(__LINE__, &sd_out.recv_id, sizeof(sd_out.recv_id), &sd_in.recv_id, sizeof(sd_in.recv_id));
	cmp(__LINE__, &sd_out.request_id, sizeof(sd_out.request_id), &sd_in.request_id, sizeof(sd_in.request_id));
	cmp(__LINE__, &sd_out.datum_info.num_fixed_data, sizeof(sd_out.datum_info.num_fixed_data), &sd_in.datum_info.num_fixed_data, sizeof(sd_in.datum_info.num_fixed_data));
	cmp(__LINE__, &sd_out.datum_info.num_variable_data, sizeof(sd_out.datum_info.num_variable_data), &sd_in.datum_info.num_variable_data, sizeof(sd_in.datum_info.num_variable_data));
	dis_fixed_datum *fixed_datum_out = sd_out.datum_info.fixed_datum;
	cmp(__LINE__, fixed_datum_out, sizeof(*fixed_datum_out), &fixed_datum_in, sizeof(fixed_datum_in));
	dis_variable_datum *var_out = sd_out.datum_info.variable_datum;
	cmp(__LINE__, &var_out->datum_id, sizeof(var_out->datum_id), &variable_datum_in.datum_id, sizeof(variable_datum_in.datum_id));
	cmp(__LINE__, &var_out->value_length, sizeof(var_out->value_length), &variable_datum_in.value_length, sizeof(variable_datum_in.value_length));
	cmp(__LINE__, var_out->value.ptr_value, var_out->value_length/8, variable_datum_in.value.ptr_value, variable_datum_in.value_length/8);
	//printf("value=%8s..., len=%ju\n", var_out->value.ptr_value,
	//		(uintmax_t) var_out->value_length);
	dis_freePDUComponents((dis_pdu *) &sd_out);
}


static void test_dis_stop_pdu()
{
	xdr_Type *xdr;
	char      buf[2000];
	int       buf_len_in, buf_len_out;
	dis_stop_pdu stop_in, stop_out;
	
	fill(&stop_in, sizeof(stop_in));
	stop_in.hdr.protocol_version = DISProtocolVersionIEEE1278_95;
	stop_in.hdr.pdu_type = PDUTypeStopFreeze; // pkt offset 2
	stop_in.hdr.protocol_family = PDUFamilySimulationManagement; // pkt offset 3
	stop_in.hdr.length = 0; // set below
	stop_in.hdr.padding = 0;
	
	xdr = xdr_new(buf, sizeof(buf), xdr_ENCODE);
	assert( xdr_dis_pdu(xdr, (dis_pdu *) &stop_in) );
	buf_len_in = xdr_getpos(xdr);
	xdr_free(xdr);
/*
 *  Now for a hack. We need to insert the correct packet length into
 *  the PDU header.  The header is somewhat stable from one protocol release
 *  to the next, so I've just hard-coded it here.
 */

	stop_in.hdr.length = buf_len_in;
	*((u_short *) &buf[8]) = htons(buf_len_in);
	
	if( IS_LITTLE_ENDIAN ){ // sorry, only little endian cpu here
		// Compares the generated packet with the expected one:
		char *exp_buf = 
		"\x05\x02\x0e\x05\x08\x07\x06\x05\x00\x28\x00\x00\x0e\x0d\x10\x0f"
		"\x12\x11\x14\x13\x16\x15\x18\x17\x1c\x1b\x1a\x19\x20\x1f\x1e\x1d"
		"\x21\x22\x23\x24\x28\x27\x26\x25";
		int exp_buf_len = 2*16+8;
		cmp(__LINE__, buf, buf_len_in, exp_buf, exp_buf_len);
	}
	
	// Decodes the generated packet:
	memory_zero(&stop_out);
	xdr = xdr_new(buf, buf_len_in, xdr_DECODE);
	assert( xdr_dis_pdu(xdr, (dis_pdu *) &stop_out) );
	buf_len_out = xdr_getpos(xdr);
	xdr_free(xdr);
	
	// Compares the decoded data with the original data:
	assert(buf_len_out == buf_len_in);
	cmp(__LINE__, &stop_out.hdr, sizeof(stop_out.hdr), &stop_in.hdr, sizeof(stop_in.hdr));
	cmp(__LINE__, &stop_out.orig_id, sizeof(stop_out.orig_id), &stop_in.orig_id, sizeof(stop_in.orig_id));
	cmp(__LINE__, &stop_out.recv_id, sizeof(stop_out.recv_id), &stop_in.recv_id, sizeof(stop_in.recv_id));
	cmp(__LINE__, &stop_out.real_time, sizeof(stop_out.real_time), &stop_in.real_time, sizeof(stop_in.real_time));
	cmp(__LINE__, &stop_out.reason, sizeof(stop_out.reason), &stop_in.reason, sizeof(stop_in.reason));
	cmp(__LINE__, &stop_out.behavior, sizeof(stop_out.behavior), &stop_in.behavior, sizeof(stop_in.behavior));
	cmp(__LINE__, &stop_out.request_id, sizeof(stop_out.request_id), &stop_in.request_id, sizeof(stop_in.request_id));
	dis_freePDUComponents((dis_pdu *) &stop_out);
}


static void test_dis_start_pdu()
{
	xdr_Type *xdr;
	char      buf[2000];
	int       buf_len_in, buf_len_out;
	dis_start_pdu start_in, start_out;
	
	fill(&start_in, sizeof(start_in));
	start_in.hdr.protocol_version = DISProtocolVersionIEEE1278_95;
	start_in.hdr.pdu_type = PDUTypeStartResume; // pkt offset 2
	start_in.hdr.protocol_family = PDUFamilySimulationManagement; // pkt offset 3
	start_in.hdr.length = 0; // set below
	start_in.hdr.padding = 0;
	
	xdr = xdr_new(buf, sizeof(buf), xdr_ENCODE);
	assert( xdr_dis_pdu(xdr, (dis_pdu *) &start_in) );
	buf_len_in = xdr_getpos(xdr);
	xdr_free(xdr);
/*
 *  Now for a hack. We need to insert the correct packet length into
 *  the PDU header.  The header is somewhat stable from one protocol release
 *  to the next, so I've just hard-coded it here.
 */

	start_in.hdr.length = buf_len_in;
	*((u_short *) &buf[8]) = htons(buf_len_in);
	
	if( IS_LITTLE_ENDIAN ){ // sorry, only little endian cpu here
		// Compares the generated packet with the expected one:
		char *exp_buf = 
		"\x05\x02\x0d\x05\x08\x07\x06\x05\x00\x2c\x00\x00\x0e\x0d\x10\x0f"
		"\x12\x11\x14\x13\x16\x15\x18\x17\x1c\x1b\x1a\x19\x20\x1f\x1e\x1d"
		"\x24\x23\x22\x21\x28\x27\x26\x25\x2c\x2b\x2a\x29";
		int exp_buf_len = 2*16+12;
		cmp(__LINE__, buf, buf_len_in, exp_buf, exp_buf_len);
	}
	
	// Decodes the generated packet:
	memory_zero(&start_out);
	xdr = xdr_new(buf, buf_len_in, xdr_DECODE);
	assert( xdr_dis_pdu(xdr, (dis_pdu *) &start_out) );
	buf_len_out = xdr_getpos(xdr);
	xdr_free(xdr);
	
	// Compares the decoded data with the original data:
	assert(buf_len_out == buf_len_in);
	cmp(__LINE__, &start_out.hdr, sizeof(start_out.hdr), &start_in.hdr, sizeof(start_in.hdr));
	cmp(__LINE__, &start_out.orig_id, sizeof(start_out.orig_id), &start_in.orig_id, sizeof(start_in.orig_id));
	cmp(__LINE__, &start_out.recv_id, sizeof(start_out.recv_id), &start_in.recv_id, sizeof(start_in.recv_id));
	cmp(__LINE__, &start_out.real_time, sizeof(start_out.real_time), &start_in.real_time, sizeof(start_in.real_time));
	cmp(__LINE__, &start_out.sim_time, sizeof(start_out.sim_time), &start_in.sim_time, sizeof(start_in.sim_time));
	cmp(__LINE__, &start_out.request_id, sizeof(start_out.request_id), &start_in.request_id, sizeof(start_in.request_id));
	dis_freePDUComponents((dis_pdu *) &start_out);
}


static void test_dis_transfer_control_pdu()
{
	xdr_Type *xdr;
	char      buf[2000];
	int       buf_len_in, buf_len_out;
	dis_transfer_control_pdu tc_in, tc_out;
	
	fill(&tc_in, sizeof(tc_in));
	tc_in.hdr.protocol_version = DISProtocolVersionIEEE1278_95;
	tc_in.hdr.pdu_type = PDUTypeTransferControl; // pkt offset 2
	tc_in.hdr.protocol_family = PDUFamilyOther; // pkt offset 3
	tc_in.hdr.length = 0; // set below
	tc_in.hdr.padding = 0;
	
	xdr = xdr_new(buf, sizeof(buf), xdr_ENCODE);
	assert( xdr_dis_pdu(xdr, (dis_pdu *) &tc_in) );
	buf_len_in = xdr_getpos(xdr);
	xdr_free(xdr);
/*
 *  Now for a hack. We need to insert the correct packet length into
 *  the PDU header.  The header is somewhat stable from one protocol release
 *  to the next, so I've just hard-coded it here.
 */

	tc_in.hdr.length = buf_len_in;
	*((u_short *) &buf[8]) = htons(buf_len_in);
	
	if( IS_LITTLE_ENDIAN ){ // sorry, only little endian cpu here
		// Compares the generated packet with the expected one:
		char *exp_buf = 
		"\x05\x02\x9c\x00\x08\x07\x06\x05\x00\x28\x00\x00\x0e\x0d\x10\x0f"
		"\x12\x11\x14\x13\x16\x15\x18\x17\x1c\x1b\x1a\x19\x1d\x1e\x20\x1f"
		"\x22\x21\x24\x23\x28\x27\x26\x25";
		int exp_buf_len = 2*16+8;
		cmp(__LINE__, buf, buf_len_in, exp_buf, exp_buf_len);
	}
	
	// Decodes the generated packet:
	memory_zero(&tc_out);
	xdr = xdr_new(buf, buf_len_in, xdr_DECODE);
	assert( xdr_dis_pdu(xdr, (dis_pdu *) &tc_out) );
	buf_len_out = xdr_getpos(xdr);
	xdr_free(xdr);
	
	// Compares the decoded data with the original data:
	assert(buf_len_out == buf_len_in);
	cmp(__LINE__, &tc_out.hdr, sizeof(tc_out.hdr), &tc_in.hdr, sizeof(tc_in.hdr));
	cmp(__LINE__, &tc_out.orig_id, sizeof(tc_out.orig_id), &tc_in.orig_id, sizeof(tc_in.orig_id));
	cmp(__LINE__, &tc_out.recv_id, sizeof(tc_out.recv_id), &tc_in.recv_id, sizeof(tc_in.recv_id));
	cmp(__LINE__, &tc_out.request_id, sizeof(tc_out.request_id), &tc_in.request_id, sizeof(tc_in.request_id));
	cmp(__LINE__, &tc_out.reliability_service, sizeof(tc_out.reliability_service), &tc_in.reliability_service, sizeof(tc_in.reliability_service));
	cmp(__LINE__, &tc_out.transfer_type, sizeof(tc_out.transfer_type), &tc_in.transfer_type, sizeof(tc_in.transfer_type));
	cmp(__LINE__, &tc_out.target_id, sizeof(tc_out.target_id), &tc_in.target_id, sizeof(tc_in.target_id));
	cmp(__LINE__, &tc_out.num_record_sets, sizeof(tc_out.num_record_sets), &tc_in.num_record_sets, sizeof(tc_in.num_record_sets));
	dis_freePDUComponents((dis_pdu *) &tc_out);
}


static void test_dis_acknowledge_pdu()
{
	xdr_Type *xdr;
	char      buf[2000];
	int       buf_len_in, buf_len_out;
	dis_acknowledge_pdu ack_in, ack_out;
	
	fill(&ack_in, sizeof(ack_in));
	ack_in.hdr.protocol_version = DISProtocolVersionIEEE1278_95;
	ack_in.hdr.pdu_type = PDUTypeAcknowledge; // pkt offset 2
	ack_in.hdr.protocol_family = PDUFamilySimulationManagement; // pkt offset 3
	ack_in.hdr.length = 0; // set below
	ack_in.hdr.padding = 0;
	
	xdr = xdr_new(buf, sizeof(buf), xdr_ENCODE);
	assert( xdr_dis_pdu(xdr, (dis_pdu *) &ack_in) );
	buf_len_in = xdr_getpos(xdr);
	xdr_free(xdr);
/*
 *  Now for a hack. We need to insert the correct packet length into
 *  the PDU header.  The header is somewhat stable from one protocol release
 *  to the next, so I've just hard-coded it here.
 */

	ack_in.hdr.length = buf_len_in;
	*((u_short *) &buf[8]) = htons(buf_len_in);
	
	if( IS_LITTLE_ENDIAN ){ // sorry, only little endian cpu here
		// Compares the generated packet with the expected one:
		char *exp_buf = 
		"\x05\x02\x0f\x05\x08\x07\x06\x05\x00\x20\x00\x00\x0e\x0d\x10\x0f"
		"\x12\x11\x14\x13\x16\x15\x18\x17\x1a\x19\x1c\x1b\x20\x1f\x1e\x1d";
		int exp_buf_len = 2*16;
		cmp(__LINE__, buf, buf_len_in, exp_buf, exp_buf_len);
	}
	
	// Decodes the generated packet:
	memory_zero(&ack_out);
	xdr = xdr_new(buf, buf_len_in, xdr_DECODE);
	assert( xdr_dis_pdu(xdr, (dis_pdu *) &ack_out) );
	buf_len_out = xdr_getpos(xdr);
	xdr_free(xdr);
	
	// Compares the decoded data with the original data:
	assert(buf_len_out == buf_len_in);
	cmp(__LINE__, &ack_out.hdr, sizeof(ack_out.hdr), &ack_in.hdr, sizeof(ack_in.hdr));
	cmp(__LINE__, &ack_out.orig_id, sizeof(ack_out.orig_id), &ack_in.orig_id, sizeof(ack_in.orig_id));
	cmp(__LINE__, &ack_out.recv_id, sizeof(ack_out.recv_id), &ack_in.recv_id, sizeof(ack_in.recv_id));
	cmp(__LINE__, &ack_out.acknowledge_flag, sizeof(ack_out.acknowledge_flag), &ack_in.acknowledge_flag, sizeof(ack_in.acknowledge_flag));
	cmp(__LINE__, &ack_out.resp_flag, sizeof(ack_out.resp_flag), &ack_in.resp_flag, sizeof(ack_in.resp_flag));
	cmp(__LINE__, &ack_out.request_id, sizeof(ack_out.request_id), &ack_in.request_id, sizeof(ack_in.request_id));
	dis_freePDUComponents((dis_pdu *) &ack_out);
}


static void test_dis_comment_pdu()
{
	xdr_Type *xdr;
	char      buf[2000];
	int       buf_len_in, buf_len_out;
	dis_comment_pdu msg_in, msg_out;
	dis_fixed_datum fixed_datum_in;
	dis_variable_datum variable_datum_in;
	
	fill(&msg_in, sizeof(msg_in));
	msg_in.hdr.protocol_version = DISProtocolVersionIEEE1278_95;
	msg_in.hdr.pdu_type = PDUTypeComment; // pkt offset 2
	msg_in.hdr.protocol_family = PDUFamilySimulationManagement; // pkt offset 3
	msg_in.hdr.length = 0; // set below
	msg_in.hdr.padding = 0;
	
	msg_in.num_fixed_data = 1;
	fill(&fixed_datum_in, sizeof(fixed_datum_in));
	msg_in.fixed_datum = &fixed_datum_in;
	
	msg_in.num_variable_data = 1;
	msg_in.variable_datum = &variable_datum_in;
	variable_datum_in.datum_id = datum_Name;
	/*
	 * "The length field shall specify the length of the variable datum in bits.
	 * The field of Variable Datum Value shall be padded at the end to make the
	 * length a multiple of 64-bits."
	 */
	char *s = "AAAAAAAA";
	
	variable_datum_in.value.ptr_value = (unsigned char *) s;
	variable_datum_in.value_length = 8*strlen(s);
	
	xdr = xdr_new(buf, sizeof(buf), xdr_ENCODE);
	assert( xdr_dis_pdu(xdr, (dis_pdu *) &msg_in) );
	buf_len_in = xdr_getpos(xdr);
	xdr_free(xdr);
/*
 *  Now for a hack. We need to insert the correct packet length into
 *  the PDU header.  The header is somewhat stable from one protocol release
 *  to the next, so I've just hard-coded it here.
 */

	msg_in.hdr.length = buf_len_in;
	*((u_short *) &buf[8]) = htons(buf_len_in);
	
	if( IS_LITTLE_ENDIAN ){ // sorry, only little endian cpu here
		// Compares the generated packet with the expected one:
		char *exp_buf = 
		"\x05\x02\x16\x05\x08\x07\x06\x05\x00\x38\x00\x00\x0e\x0d\x10\x0f"
		"\x12\x11\x14\x13\x16\x15\x18\x17\x00\x00\x00\x01\x00\x00\x00\x01"
		"\x04\x03\x02\x01\x08\x07\x06\x05\x00\x00\xa8\x5c\x00\x00\x00\x40"
		"\x41\x41\x41\x41\x41\x41\x41\x41";
		int exp_buf_len = 3*16 + 8;
		cmp(__LINE__, buf, buf_len_in, exp_buf, exp_buf_len);
	}
	
	// Decodes the generated packet:
	memory_zero(&msg_out);
	xdr = xdr_new(buf, buf_len_in, xdr_DECODE);
	assert( xdr_dis_pdu(xdr, (dis_pdu *) &msg_out) );
	buf_len_out = xdr_getpos(xdr);
	xdr_free(xdr);
	
	// Compares the decoded data with the original data:
	assert(buf_len_out == buf_len_in);
	cmp(__LINE__, &msg_out.hdr, sizeof(msg_out.hdr), &msg_in.hdr, sizeof(msg_in.hdr));
	cmp(__LINE__, &msg_out.orig_id, sizeof(msg_out.orig_id), &msg_in.orig_id, sizeof(msg_in.orig_id));
	cmp(__LINE__, &msg_out.recv_id, sizeof(msg_out.recv_id), &msg_in.recv_id, sizeof(msg_in.recv_id));
	cmp(__LINE__, &msg_out.num_fixed_data, sizeof(msg_out.num_fixed_data), &msg_in.num_fixed_data, sizeof(msg_in.num_fixed_data));
	cmp(__LINE__, &msg_out.num_variable_data, sizeof(msg_out.num_variable_data), &msg_in.num_variable_data, sizeof(msg_in.num_variable_data));
	
	dis_fixed_datum *fixed_datum_out = msg_out.fixed_datum;
	cmp(__LINE__, &fixed_datum_out->datum_id, sizeof(fixed_datum_out->datum_id), &fixed_datum_in.datum_id, sizeof(fixed_datum_in.datum_id));
	cmp(__LINE__, &fixed_datum_out->value, sizeof(fixed_datum_out->value), &fixed_datum_in.value, sizeof(fixed_datum_in.value));
	
	dis_variable_datum *variable_datum_out = &msg_out.variable_datum[0];
	cmp(__LINE__, &variable_datum_out->datum_id, sizeof(variable_datum_out->datum_id), &variable_datum_in.datum_id, sizeof(variable_datum_in.datum_id));
	cmp(__LINE__, &variable_datum_out->value_length, sizeof(variable_datum_out->value_length), &variable_datum_in.value_length, sizeof(variable_datum_in.value_length));
	cmp(__LINE__, variable_datum_out->value.ptr_value, variable_datum_out->value_length/8, variable_datum_in.value.ptr_value, variable_datum_in.value_length/8);
	dis_freePDUComponents((dis_pdu *) &msg_out);
}


int main(int argc, char** argv)
{
	error_prog_name = argv[0];
	
	test_dis_entity_state_pdu();
	test_dis_fire_pdu();
	test_dis_detonation_pdu();
	test_dis_emission_pdu();
	test_dis_set_data_pdu();
	test_dis_stop_pdu();
	test_dis_start_pdu();
	test_dis_transfer_control_pdu();
	test_dis_acknowledge_pdu();
	test_dis_comment_pdu();
	
	err += memory_report();
	
	return err == 0? 0 : 1;
}
