/*
 *			GPAC - MPEG-4 Systems C Development Kit
 *
 *			Copyright (c) Jean Le Feuvre 2000-2005 
 *					All rights reserved
 *
 *  This file is part of GPAC / Object Descriptor sub-project
 *
 *  GPAC is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2, or (at your option)
 *  any later version.
 *   
 *  GPAC 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 General Public License for more details.
 *   
 *  You should have received a copy of the GNU General Public License
 *  along with GNU Make; see the file COPYING.  If not, write to
 *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. 
 *
 */

#include <gpac/intern/m4_od_dev.h>

#if defined (WIN32) && !defined(__GNUC__)
#define LLD "%I64d"
#else
#define LLD "%lld"
#endif


#define IPMPX_MAX_TREE		100

#define IPMPX_FORMAT_INDENT( ind_buf, indent ) \
	{ \
		u32 z;	\
		assert(IPMPX_MAX_TREE>indent);	\
		for (z=0; z<indent; z++) ind_buf[z] = ' '; \
		ind_buf[z] = 0; \
	} \


static void StartList(FILE *trace, char *name, u32 indent, Bool XMTDump)
{
	char ind_buf[IPMPX_MAX_TREE];
	IPMPX_FORMAT_INDENT(ind_buf, indent);
	if (XMTDump) {
		fprintf(trace, "%s<%s>\n", ind_buf, name);
	} else {
		fprintf(trace, "%s%s [\n", ind_buf, name);
	}
}
static void EndList(FILE *trace, char *name, u32 indent, Bool XMTDump)
{
	char ind_buf[IPMPX_MAX_TREE];
	IPMPX_FORMAT_INDENT(ind_buf, indent);
	if (XMTDump) {
		fprintf(trace, "%s</%s>\n", ind_buf, name);
	} else {
		fprintf(trace, "%s]\n", ind_buf);
	}
}

static void StartElement(FILE *trace, char *descName, u32 indent, Bool XMTDump)
{
	char ind_buf[IPMPX_MAX_TREE];
	IPMPX_FORMAT_INDENT(ind_buf, indent);

	fprintf(trace, "%s", ind_buf);
	if (!XMTDump) {
		fprintf(trace, "%s {\n", descName);
	} else {
		fprintf(trace, "<%s ", descName);
	}
}

static void EndAttributes(FILE *trace, Bool XMTDump, Bool has_children)
{
	if (XMTDump) {
		if (has_children) {
			fprintf(trace, ">\n");
		} else {
			fprintf(trace, "/>\n");
		}
	}
}

static void EndElement(FILE *trace, char *descName, u32 indent, Bool XMTDump)
{
	char ind_buf[IPMPX_MAX_TREE];
	IPMPX_FORMAT_INDENT(ind_buf, indent);

	fprintf(trace, "%s", ind_buf);
	if (!XMTDump) {
		fprintf(trace, "}\n");
	} else {
		fprintf(trace, "</%s>\n", descName);
	}
}

static void StartAttribute(FILE *trace, char *attName, u32 indent, Bool XMTDump)
{
	char ind_buf[IPMPX_MAX_TREE];
	IPMPX_FORMAT_INDENT(ind_buf, indent);
	if (!XMTDump) {
		fprintf(trace, "%s%s ", ind_buf, attName);
	} else {
		fprintf(trace, "%s=\"", attName);
	}
}
static void EndAttribute(FILE *trace, u32 indent, Bool XMTDump)
{
	if (!XMTDump) {
		fprintf(trace, "\n");
	} else {
		fprintf(trace, "\" ");
	}
}

static void DumpInt(FILE *trace, char *attName, u32  val, u32 indent, Bool XMTDump)
{
	if (!val) return;
	StartAttribute(trace, attName, indent, XMTDump);
	fprintf(trace, "%d", val);
	EndAttribute(trace, indent, XMTDump);
}

static void DumpLargeInt(FILE *trace, char *attName, u64  val, u32 indent, Bool XMTDump)
{
	if (!val) return;
	StartAttribute(trace, attName, indent, XMTDump);
	fprintf(trace, LLD, val);
	EndAttribute(trace, indent, XMTDump);
}

static void DumpBool(FILE *trace, char *attName, u32  val, u32 indent, Bool XMTDump)
{
	if (!val) return;

	StartAttribute(trace, attName, indent, XMTDump);
	fprintf(trace, "%s", val ? "true" : "false");
	EndAttribute(trace, indent, XMTDump);
}

static void DumpData(FILE *trace, char *name, char *data, u32 dataLength, u32 indent, Bool XMTDump)
{
	u32 i;
	Bool ASCII_Dump;
	if (!name && !data) return;

	if (name) StartAttribute(trace, name, indent, XMTDump);
	if (!XMTDump) fprintf(trace, "\"");

	ASCII_Dump = 1;
	for (i=0; i<dataLength; i++) {
		if ((data[i]<32) || (data[i]>126)) {
			ASCII_Dump = 0;
			break;
		}
	}
	if (!ASCII_Dump && XMTDump) fprintf(trace, "data:application/octet-string,");
	for (i=0; i<dataLength; i++) {
		if (ASCII_Dump) {
			fprintf(trace, "%c", (unsigned char) data[i]);
		} else {
			fprintf(trace, "%%");
			fprintf(trace, "%02X", (unsigned char) data[i]);
		}
	}
	if (!XMTDump) fprintf(trace, "\"");
	if (name) EndAttribute(trace, indent, XMTDump);
}
static void DumpData_16(FILE *trace, char *name, u16 *data, u16 dataLength, u32 indent, Bool XMTDump)
{
	u32 i;
	if (!name && !data) return;
	if (name) StartAttribute(trace, name, indent, XMTDump);
	if (!XMTDump) fprintf(trace, "\"");
	for (i=0; i<dataLength; i++) {
		if (XMTDump) {
			fprintf(trace, "\'%d\'", data[i]);
			if (i+1<dataLength) fprintf(trace, " ");
		} else {
			fprintf(trace, "%d", data[i]);
			if (i+1<dataLength) fprintf(trace, ", ");
		}
	}
	if (!XMTDump) fprintf(trace, "\"");
	if (name) EndAttribute(trace, indent, XMTDump);
}
static void DumpBin128(FILE *trace, char *name, char *data, u32 indent, Bool XMTDump)
{
	u32 i;
	if (!name ||!data) return;
	StartAttribute(trace, name, indent, XMTDump);
	fprintf(trace, "0x");
	i=0;
	while (!data[i] && (i<16)) i++;
	if (i==16) {
		fprintf(trace, "00");
	} else {
		for (; i<16; i++) fprintf(trace, "%02X", (unsigned char) data[i]);
	}
	EndAttribute(trace, indent, XMTDump);
}


static void DumpDate(FILE *trace, char *name, char *data, u32 indent, Bool XMTDump)
{
	u32 i;
	if (!name ||!data) return;
	StartAttribute(trace, name, indent, XMTDump);
	fprintf(trace, "0x");
	for (i=0; i<5; i++) fprintf(trace, "%02X", (unsigned char) data[i]);
	EndAttribute(trace, indent, XMTDump);
}

void DumpIPMPX_ByteArray(IPMPX_ByteArray *_p, char *attName, FILE *trace, u32 indent, Bool XMTDump)
{
	if (_p->data) {
		if (XMTDump) {
			StartElement(trace, attName ? attName : "ByteArray", indent, XMTDump);
			indent++;
			DumpData(trace, "array", _p->data, _p->length, indent, XMTDump);
			indent--;
			EndAttributes(trace, 1, 0);
		} else {
			DumpData(trace, attName ? attName : "ByteArray", _p->data, _p->length, indent, 0);
		}
	}
}


void DumpIPMPX_AUTH(IPMPX_Authentication *ipa, FILE *trace, u32 indent, Bool XMTDump)
{
	switch (ipa->tag) {
	case IPMPX_AUTH_KeyDescr_Tag:
	{
		IPMPX_AUTH_KeyDescriptor *p = (IPMPX_AUTH_KeyDescriptor *)ipa;
		StartElement(trace, "IPMP_KeyDescriptor", indent, XMTDump);
		DumpData(trace, "keyBody", p->keyBody, p->keyBodyLength, indent+1, XMTDump);
		if (XMTDump) EndAttributes(trace, 1, 0);
		else EndElement(trace, "", indent, 0);
	}
		break;
	case IPMPX_AUTH_AlgorithmDescr_Tag:
	{
		IPMPX_AUTH_AlgorithmDescriptor *p = (IPMPX_AUTH_AlgorithmDescriptor *)ipa;
		StartElement(trace, "IPMP_AlgorithmDescriptor", indent, XMTDump);
		if (p->regAlgoID) {
			DumpInt(trace, "regAlgoID", p->regAlgoID, indent+1, XMTDump);
		} else {
			DumpIPMPX_ByteArray(p->specAlgoID, "specAlgoID", trace, indent+1, XMTDump);
		}
		EndAttributes(trace, XMTDump, 1);
		if (p->OpaqueData) DumpIPMPX_ByteArray(p->OpaqueData, "OpaqueData", trace, indent+1, XMTDump);

		EndElement(trace, "IPMP_AlgorithmDescriptor", indent, XMTDump);
	}
		break;
	}
}

void DumpIPMPX_BaseData(IPMPX_Data *_p, FILE *trace, u32 indent, Bool XMTDump)
{
#if 0
	if (XMTDump) {
		StartElement(trace, "IPMP_BaseData", indent, XMTDump);
		DumpInt(trace, "dataID", _p->dataID, indent, 1);
		DumpInt(trace, "Version", _p->Version, indent, 1);
		EndLeafAttribute(trace, indent, XMTDump);
	} else {
		DumpInt(trace, "dataID", _p->dataID, indent, 0);
		DumpInt(trace, "Version", _p->Version, indent, 0);
	}
#endif
}

M4Err DumpIPMPX_OpaqueData(IPMPX_Data *_p, FILE *trace, u32 indent, Bool XMTDump)
{
	IPMPX_OpaqueData *p = (IPMPX_OpaqueData *)_p;

	StartElement(trace, (p->tag==IPMPX_RightsData_Tag) ? "IPMP_RightsData" : "IPMP_OpaqueData", indent, XMTDump);
	indent++;
	EndAttributes(trace, XMTDump, 1);
	DumpIPMPX_BaseData(_p, trace, indent, XMTDump);
	DumpIPMPX_ByteArray(p->opaqueData, (p->tag==IPMPX_RightsData_Tag) ? "rightsInfo" : "opaqueData", trace, indent, XMTDump);
	indent--;
	EndElement(trace, (p->tag==IPMPX_RightsData_Tag) ? "IPMP_RightsData" : "IPMP_OpaqueData", indent, XMTDump);
	return M4OK;
}

M4Err DumpIPMPX_KeyData(IPMPX_Data *_p, FILE *trace, u32 indent, Bool XMTDump)
{
	IPMPX_KeyData*p = (IPMPX_KeyData*)_p;

	StartElement(trace, "IPMP_KeyData", indent, XMTDump);
	indent++;

	DumpBool(trace, "hasStartDTS", (p->flags & 1) ? 1 : 0, indent, XMTDump);
	DumpBool(trace, "hasStartPacketID", (p->flags & 2) ? 1 : 0, indent, XMTDump);
	DumpBool(trace, "hasEndDTS", (p->flags & 4) ? 1 : 0, indent, XMTDump);
	DumpBool(trace, "hasEndPacketID", (p->flags & 8) ? 1 : 0, indent, XMTDump);

	if (p->flags & 1) DumpLargeInt(trace, "startDTS", p->startDTS, indent, XMTDump);
	if (p->flags & 2) DumpInt(trace, "startPacketID", p->startPacketID, indent, XMTDump);
	if (p->flags & 4) DumpLargeInt(trace, "expireDTS", p->expireDTS, indent, XMTDump);
	if (p->flags & 8) DumpInt(trace, "expirePacketID", p->expirePacketID, indent, XMTDump);

	EndAttributes(trace, XMTDump, 1);
	DumpIPMPX_BaseData(_p, trace, indent, XMTDump);
	DumpIPMPX_ByteArray(p->keyBody, "keyBody", trace, indent, XMTDump);
	DumpIPMPX_ByteArray(p->OpaqueData, "OpaqueData", trace, indent, XMTDump);

	indent--;
	EndElement(trace, "IPMP_KeyData", indent, XMTDump);
	return M4OK;
}
M4Err DumpIPMPX_SecureContainer(IPMPX_Data *_p, FILE *trace, u32 indent, Bool XMTDump)
{
	IPMPX_SecureContainer*p = (IPMPX_SecureContainer*)_p;
	StartElement(trace, "IPMP_SecureContainer", indent, XMTDump);
	indent++;
	DumpBool(trace, "isMACEncrypted", p->isMACEncrypted, indent, XMTDump);
	EndAttributes(trace, XMTDump, 1);
	DumpIPMPX_BaseData(_p, trace, indent, XMTDump);
	if (p->encryptedData) DumpIPMPX_ByteArray(p->encryptedData, "encryptedData", trace, indent, XMTDump);
	if (p->protectedMsg) IPMPX_DumpData(p->protectedMsg, trace, indent, XMTDump);
	if (p->MAC) DumpIPMPX_ByteArray(p->MAC, "MAC", trace, indent, XMTDump);
	indent--;
	EndElement(trace, "IPMP_SecureContainer", indent, XMTDump);
	return M4OK;
}
M4Err DumpIPMPX_InitAuthentication(IPMPX_Data *_p, FILE *trace, u32 indent, Bool XMTDump)
{
	IPMPX_InitAuthentication*p = (IPMPX_InitAuthentication*)_p;
	StartElement(trace, "IPMP_InitAuthentication", indent, XMTDump);
	indent++;
	DumpInt(trace, "Context", p->Context, indent, XMTDump);
	DumpInt(trace, "AuthType", p->AuthType, indent, XMTDump);
	EndAttributes(trace, XMTDump, 1);
	DumpIPMPX_BaseData(_p, trace, indent, XMTDump);
	indent--;
	EndElement(trace, "IPMP_InitAuthentication", indent, XMTDump);
	return M4OK;
}

M4Err DumpIPMPX_TrustSecurityMetadata(IPMPX_Data *_p, FILE *trace, u32 indent, Bool XMTDump)
{
	u32 i, j;
	IPMPX_TrustSecurityMetadata*p = (IPMPX_TrustSecurityMetadata*)_p;
	StartElement(trace, "IPMP_TrustSecurityMetadata", indent, XMTDump);
	indent++;
	EndAttributes(trace, XMTDump, 1);
	DumpIPMPX_BaseData(_p, trace, indent, XMTDump);

	StartList(trace, "trustedTools", indent, XMTDump);
	indent++;

	for (i=0; i<ChainGetCount(p->TrustedTools); i++) {
		IPMPX_TrustedTool *tt = ChainGetEntry(p->TrustedTools, i);
		StartElement(trace, "IPMP_TrustedTool", indent, XMTDump);
		indent++;
		DumpBin128(trace, "toolID", (char *)tt->toolID, indent, XMTDump);
		DumpDate(trace, "AuditDate", tt->AuditDate, indent, XMTDump);
		EndAttributes(trace, XMTDump, 1);
		StartList(trace, "trustSpecifications", indent, XMTDump);
		indent++;
		for (j=0; j<ChainGetCount(tt->trustSpecifications); j++) {
			IPMPX_TrustSpecification *ts = ChainGetEntry(tt->trustSpecifications, j);
			StartElement(trace, "IPMP_TrustSpecification", indent, XMTDump);
			indent++;
			DumpDate(trace, "startDate", ts->startDate, indent, XMTDump);
			DumpInt(trace, "attackerProfile", ts->attackerProfile, indent, XMTDump);
			DumpInt(trace, "trustedDuration", ts->trustedDuration, indent, XMTDump);
			EndAttributes(trace, XMTDump, 1);
			if (ts->CCTrustMetadata) DumpIPMPX_ByteArray(ts->CCTrustMetadata, "CCTrustMetadata", trace, indent, XMTDump);
			indent--;
			EndElement(trace, "IPMP_TrustSpecification", indent, XMTDump);
		}
		indent--;
		EndList(trace, "trustSpecifications", indent, XMTDump);
		indent--;
		EndElement(trace, "IPMP_TrustedTool", indent, XMTDump);
	}
	indent--;
	EndList(trace, "trustedTools", indent, XMTDump);

	indent--;
	EndElement(trace, "IPMP_TrustSecurityMetadata", indent, XMTDump);
	return M4OK;
}

M4Err DumpIPMPX_MutualAuthentication(IPMPX_Data *_p, FILE *trace, u32 indent, Bool XMTDump)
{
	u32 i, count;
	IPMPX_MutualAuthentication *p = (IPMPX_MutualAuthentication*)_p;
	StartElement(trace, "IPMP_MutualAuthentication", indent, XMTDump);
	indent++;
	DumpBool(trace, "failedNegotiation", p->failedNegotiation, indent, XMTDump);
	if (ChainGetCount(p->certificates)) DumpInt(trace, "certType", p->certType, indent, XMTDump);

	EndAttributes(trace, XMTDump, 1);
	DumpIPMPX_BaseData(_p, trace, indent, XMTDump);

	StartList(trace, "candidateAlgorithms", indent, XMTDump);
	count = ChainGetCount(p->candidateAlgorithms);
	indent++;
	for (i=0; i<count; i++) {
		IPMPX_Authentication *ip_auth = ChainGetEntry(p->candidateAlgorithms, i);
		DumpIPMPX_AUTH(ip_auth, trace, indent, XMTDump);
	}
	indent--;
	EndList(trace, "candidateAlgorithms", indent, XMTDump);
	
	StartList(trace, "agreedAlgorithms", indent, XMTDump);
	count = ChainGetCount(p->agreedAlgorithms);
	indent++;
	for (i=0; i<count; i++) {
		IPMPX_Authentication *ip_auth = ChainGetEntry(p->agreedAlgorithms, i);
		DumpIPMPX_AUTH(ip_auth, trace, indent, XMTDump);
	}
	indent--;
	EndList(trace, "agreedAlgorithms", indent, XMTDump);

	if (p->AuthenticationData) DumpIPMPX_ByteArray(p->AuthenticationData, "AuthenticationData", trace, indent, XMTDump);

	count = ChainGetCount(p->certificates);
	if (count || p->opaque || p->publicKey) {
		/*type 1*/
		if (count) {
			StartList(trace, "certificates", indent, XMTDump);
			for (i=0; i<count; i++) {
				IPMPX_ByteArray *ipd = ChainGetEntry(p->certificates, i);
				if (XMTDump) {
					DumpIPMPX_ByteArray(ipd, NULL, trace, indent, XMTDump);
				} else {
					StartAttribute(trace, "", indent, 0);
					DumpData(trace, NULL, ipd->data, ipd->length, indent, 0);
					if (i+1<count) fprintf(trace, ",");
					fprintf(trace, "\n");
				}
			}
			EndList(trace, "certificates", indent, XMTDump);
		}
		/*type 2*/
		else if (p->publicKey) {
			DumpIPMPX_AUTH((IPMPX_Authentication *) p->publicKey, trace, indent, XMTDump);
		}
		/*type 0xFE*/
		else if (p->opaque) {
			DumpIPMPX_ByteArray(p->opaque, "opaque", trace, indent, XMTDump);
		}
		if (!XMTDump) StartAttribute(trace, "trustData", indent, 0);
		else {
			StartElement(trace, "trustData", indent, XMTDump);
			EndAttributes(trace, XMTDump, 1);
		}
		IPMPX_DumpData((IPMPX_Data *)p->trustData, trace, indent, XMTDump);
		if (XMTDump) EndElement(trace, "trustData", indent, XMTDump);
		DumpIPMPX_ByteArray(p->authCodes, "authCodes", trace, indent, XMTDump);
	}

	indent--;
	EndElement(trace, "IPMP_MutualAuthentication", indent, XMTDump);
	return M4OK;
}

M4Err DumpIPMPX_GetToolsResponse(IPMPX_Data *_p, FILE *trace, u32 indent, Bool XMTDump)
{
	M4Err DumpDescList(Chain *list, FILE *trace, u32 indent, char *ListName, Bool XMTDump);

	IPMPX_GetToolsResponse*p = (IPMPX_GetToolsResponse*)_p;
	StartElement(trace, "IPMP_GetToolsResponse", indent, XMTDump);
	indent++;
	EndAttributes(trace, XMTDump, 1);
	DumpIPMPX_BaseData(_p, trace, indent, XMTDump);
	DumpDescList(p->ipmp_tools, trace, indent, "IPMP_Tools", XMTDump);
	indent--;
	EndElement(trace, "IPMP_GetToolsResponse", indent, XMTDump);
	return M4OK;
}

M4Err DumpIPMPX_ParametricDescription(IPMPX_Data *_p, FILE *trace, u32 indent, Bool XMTDump)
{
	u32 i;
	IPMPX_ParametricDescription*p = (IPMPX_ParametricDescription*)_p;
	StartElement(trace, "IPMP_ParametricDescription", indent, XMTDump);
	indent++;
	DumpInt(trace, "majorVersion", p->majorVersion, indent, XMTDump);
	DumpInt(trace, "minorVersion", p->minorVersion, indent, XMTDump);
	EndAttributes(trace, XMTDump, 1);
	DumpIPMPX_BaseData(_p, trace, indent, XMTDump);
	DumpIPMPX_ByteArray(p->descriptionComment, "descriptionComment", trace, indent, XMTDump);

	StartList(trace, "descriptions", indent, XMTDump);
	indent++;
	for (i=0; i<ChainGetCount(p->descriptions); i++) {
		IPMPX_ParametricDescriptionItem *it = ChainGetEntry(p->descriptions, i);
		StartElement(trace, "IPMP_ParametricDescriptionItem", indent, XMTDump);
		indent++;
		EndAttributes(trace, XMTDump, 1);
		DumpIPMPX_ByteArray(it->main_class, "class", trace, indent, XMTDump);
		DumpIPMPX_ByteArray(it->subClass, "subClass", trace, indent, XMTDump);
		DumpIPMPX_ByteArray(it->typeData, "typeData", trace, indent, XMTDump);
		DumpIPMPX_ByteArray(it->type, "type", trace, indent, XMTDump);
		DumpIPMPX_ByteArray(it->addedData, "addedData", trace, indent, XMTDump);
		indent--;
		EndElement(trace, "IPMP_ParametricDescriptionItem", indent, XMTDump);
	}
	indent--;
	EndList(trace, "descriptions", indent, XMTDump);

	indent--;
	EndElement(trace, "IPMP_ParametricDescription", indent, XMTDump);
	return M4OK;
}
M4Err DumpIPMPX_ToolParamCapabilitiesQuery(IPMPX_Data *_p, FILE *trace, u32 indent, Bool XMTDump)
{
	IPMPX_ToolParamCapabilitiesQuery*p = (IPMPX_ToolParamCapabilitiesQuery*)_p;
	StartElement(trace, "IPMP_ToolParamCapabilitiesQuery", indent, XMTDump);
	indent++;
	EndAttributes(trace, XMTDump, 1);
	DumpIPMPX_BaseData(_p, trace, indent, XMTDump);
	if (!XMTDump) StartAttribute(trace, "description", indent, 0);
	else {
		StartElement(trace, "description", indent, XMTDump);
		EndAttributes(trace, XMTDump, 1);
	}
	IPMPX_DumpData((IPMPX_Data *) p->description, trace, indent, XMTDump);
	if (XMTDump) EndElement(trace, "description", indent, XMTDump);

	indent--;
	EndElement(trace, "IPMP_ToolParamCapabilitiesQuery", indent, XMTDump);
	return M4OK;
}
M4Err DumpIPMPX_ToolParamCapabilitiesResponse(IPMPX_Data *_p, FILE *trace, u32 indent, Bool XMTDump)
{
	IPMPX_ToolParamCapabilitiesResponse*p = (IPMPX_ToolParamCapabilitiesResponse*)_p;
	StartElement(trace, "IPMP_ToolParamCapabilitiesResponse", indent, XMTDump);
	indent++;
	DumpBool(trace, "capabilitiesSupported", p->capabilitiesSupported, indent, XMTDump);
	EndAttributes(trace, XMTDump, 1);
	DumpIPMPX_BaseData(_p, trace, indent, XMTDump);
	indent--;
	EndElement(trace, "IPMP_ToolParamCapabilitiesResponse", indent, XMTDump);
	return M4OK;
}
M4Err DumpIPMPX_ConnectTool(IPMPX_Data *_p, FILE *trace, u32 indent, Bool XMTDump)
{
	IPMPX_ConnectTool*p = (IPMPX_ConnectTool*)_p;
	StartElement(trace, "IPMP_ConnectTool", indent, XMTDump);
	indent++;
	EndAttributes(trace, XMTDump, 1);
	DumpIPMPX_BaseData(_p, trace, indent, XMTDump);
	if (!XMTDump) StartAttribute(trace, "toolDescriptor", indent, 0);
	else {
		StartElement(trace, "toolDescriptor", indent, XMTDump);
		EndAttributes(trace, XMTDump, 1);
	}
	OD_DumpDescriptor((Descriptor *)p->toolDescriptor, trace, indent, XMTDump);
	if (XMTDump) EndElement(trace, "toolDescriptor", indent, XMTDump);

	indent--;
	EndElement(trace, "IPMP_ConnectTool", indent, XMTDump);
	return M4OK;
}
M4Err DumpIPMPX_DisconnectTool(IPMPX_Data *_p, FILE *trace, u32 indent, Bool XMTDump)
{
	IPMPX_DisconnectTool*p = (IPMPX_DisconnectTool*)_p;
	StartElement(trace, "IPMP_DisconnectTool", indent, XMTDump);
	indent++;
	DumpInt(trace, "IPMP_ToolContextID", p->IPMP_ToolContextID, indent, XMTDump);
	EndAttributes(trace, XMTDump, 1);
	DumpIPMPX_BaseData(_p, trace, indent, XMTDump);
	indent--;
	EndElement(trace, "IPMP_DisconnectTool", indent, XMTDump);
	return M4OK;
}
M4Err DumpIPMPX_GetToolContext(IPMPX_Data *_p, FILE *trace, u32 indent, Bool XMTDump)
{
	IPMPX_GetToolContext*p = (IPMPX_GetToolContext*)_p;
	StartElement(trace, "IPMP_GetToolContext", indent, XMTDump);
	indent++;
	DumpInt(trace, "scope", p->scope, indent, XMTDump);
	DumpInt(trace, "IPMP_DescriptorIDEx", p->IPMP_DescriptorIDEx, indent, XMTDump);
	EndAttributes(trace, XMTDump, 1);
	DumpIPMPX_BaseData(_p, trace, indent, XMTDump);
	indent--;
	EndElement(trace, "IPMP_GetToolContext", indent, XMTDump);
	return M4OK;
}
M4Err DumpIPMPX_GetToolContextResponse(IPMPX_Data *_p, FILE *trace, u32 indent, Bool XMTDump)
{
	IPMPX_GetToolContextResponse*p = (IPMPX_GetToolContextResponse*)_p;
	StartElement(trace, "IPMP_GetToolContextResponse", indent, XMTDump);
	indent++;
	DumpInt(trace, "OD_ID", p->OD_ID, indent, XMTDump);
	DumpInt(trace, "ESD_ID", p->ESD_ID, indent, XMTDump);
	DumpInt(trace, "IPMP_ToolContextID", p->IPMP_ToolContextID, indent, XMTDump);
	EndAttributes(trace, XMTDump, 1);
	DumpIPMPX_BaseData(_p, trace, indent, XMTDump);
	indent--;
	EndElement(trace, "IPMP_GetToolContextResponse", indent, XMTDump);
	return M4OK;
}
M4Err DumpIPMPX_AddToolNotificationListener(IPMPX_Data *_p, FILE *trace, u32 indent, Bool XMTDump)
{
	u32 i;
	IPMPX_AddToolNotificationListener*p = (IPMPX_AddToolNotificationListener*)_p;
	StartElement(trace, "IPMP_AddToolNotificationListener", indent, XMTDump);
	indent++;
	DumpInt(trace, "scope", p->scope, indent, XMTDump);
	StartAttribute(trace, "eventType", indent, XMTDump);
	if (!XMTDump) fprintf(trace, "\"");
	for (i=0; i<p->eventTypeCount; i++) {
		if (XMTDump) {
			fprintf(trace, "\'%d\'", p->eventType[i]);
			if (i+1<p->eventTypeCount) fprintf(trace, " ");
		} else {
			fprintf(trace, "%d", p->eventType[i]);
			if (i+1<p->eventTypeCount) fprintf(trace, ",");
		}
	}
	if (!XMTDump) fprintf(trace, "\"");
	EndAttribute(trace, indent, XMTDump);
	EndAttributes(trace, XMTDump, 1);
	DumpIPMPX_BaseData(_p, trace, indent, XMTDump);
	indent--;
	EndElement(trace, "IPMP_AddToolNotificationListener", indent, XMTDump);
	return M4OK;
}
M4Err DumpIPMPX_RemoveToolNotificationListener(IPMPX_Data *_p, FILE *trace, u32 indent, Bool XMTDump)
{
	u32 i;
	IPMPX_RemoveToolNotificationListener*p = (IPMPX_RemoveToolNotificationListener*)_p;
	StartElement(trace, "IPMP_RemoveToolNotificationListener", indent, XMTDump);
	indent++;
	StartAttribute(trace, "eventType", indent, XMTDump);
	if (!XMTDump) fprintf(trace, "\"");
	for (i=0; i<p->eventTypeCount; i++) {
		if (XMTDump) {
			fprintf(trace, "\'%d\'", p->eventType[i]);
			if (i+1<p->eventTypeCount) fprintf(trace, " ");
		} else {
			fprintf(trace, "%d", p->eventType[i]);
			if (i+1<p->eventTypeCount) fprintf(trace, ",");
		}
	}
	if (!XMTDump) fprintf(trace, "\"");
	EndAttribute(trace, indent, XMTDump);
	EndAttributes(trace, XMTDump, 1);
	DumpIPMPX_BaseData(_p, trace, indent, XMTDump);
	indent--;
	EndElement(trace, "IPMP_RemoveToolNotificationListener", indent, XMTDump);
	return M4OK;
}
M4Err DumpIPMPX_NotifyToolEvent(IPMPX_Data *_p, FILE *trace, u32 indent, Bool XMTDump)
{
	IPMPX_NotifyToolEvent*p = (IPMPX_NotifyToolEvent*)_p;
	StartElement(trace, "IPMP_NotifyToolEvent", indent, XMTDump);
	indent++;
	DumpInt(trace, "OD_ID", p->OD_ID, indent, XMTDump);
	DumpInt(trace, "ESD_ID", p->ESD_ID, indent, XMTDump);
	DumpInt(trace, "IPMP_ToolContextID", p->IPMP_ToolContextID, indent, XMTDump);
	DumpInt(trace, "eventType", p->eventType, indent, XMTDump);
	EndAttributes(trace, XMTDump, 1);
	DumpIPMPX_BaseData(_p, trace, indent, XMTDump);
	indent--;
	EndElement(trace, "IPMP_NotifyToolEvent", indent, XMTDump);
	return M4OK;
}
M4Err DumpIPMPX_CanProcess(IPMPX_Data *_p, FILE *trace, u32 indent, Bool XMTDump)
{
	IPMPX_CanProcess*p = (IPMPX_CanProcess*)_p;
	StartElement(trace, "IPMP_CanProcess", indent, XMTDump);
	indent++;
	DumpBool(trace, "canProcess", p->canProcess, indent, XMTDump);
	EndAttributes(trace, XMTDump, 1);
	DumpIPMPX_BaseData(_p, trace, indent, XMTDump);
	indent--;
	EndElement(trace, "IPMP_CanProcess", indent, XMTDump);
	return M4OK;
}
M4Err DumpIPMPX_ToolAPI_Config(IPMPX_Data *_p, FILE *trace, u32 indent, Bool XMTDump)
{
	IPMPX_ToolAPI_Config*p = (IPMPX_ToolAPI_Config*)_p;
	StartElement(trace, "IPMP_ToolAPI_Config", indent, XMTDump);
	indent++;
	DumpInt(trace, "Instantiation_API_ID", p->Instantiation_API_ID, indent, XMTDump);
	DumpInt(trace, "Messaging_API_ID", p->Messaging_API_ID, indent, XMTDump);
	EndAttributes(trace, XMTDump, 1);
	DumpIPMPX_BaseData(_p, trace, indent, XMTDump);
	DumpIPMPX_ByteArray(p->opaqueData, "opaqueData", trace, indent, XMTDump);
	indent--;
	EndElement(trace, "IPMP_ToolAPI_Config", indent, XMTDump);
	return M4OK;
}
M4Err DumpIPMPX_WatermarkingInit(IPMPX_Data *_p, FILE *trace, u32 indent, Bool XMTDump)
{
	IPMPX_WatermarkingInit*p = (IPMPX_WatermarkingInit*)_p;
	StartElement(trace, (_p->tag==IPMPX_AudioWatermarkingInit_Tag) ? "IPMP_AudioWatermarkingInit" : "IPMP_VideoWatermarkingInit", indent, XMTDump);
	indent++;
	DumpInt(trace, "inputFormat", p->inputFormat, indent, XMTDump);
	DumpInt(trace, "requiredOp", p->requiredOp, indent, XMTDump);
	if (p->inputFormat==0x01) {
		if (_p->tag==IPMPX_AudioWatermarkingInit_Tag) {
			DumpInt(trace, "nChannels", p->nChannels, indent, XMTDump);
			DumpInt(trace, "bitPerSample", p->bitPerSample, indent, XMTDump);
			DumpInt(trace, "frequency", p->frequency, indent, XMTDump);
		} else {
			DumpInt(trace, "frame_horizontal_size", p->frame_horizontal_size, indent, XMTDump);
			DumpInt(trace, "frame_vertical_size", p->frame_vertical_size, indent, XMTDump);
			DumpInt(trace, "chroma_format", p->chroma_format, indent, XMTDump);
		}
	}
	switch (p->requiredOp) {
	case WM_INSERT:
	case WM_REMARK:
		DumpData(trace, "wmPayload", p->wmPayload, p->wmPayloadLen, indent, XMTDump);
		break;
	case WM_EXTRACT:
	case WM_DETECT_COMPRESSION:
		DumpInt(trace, "wmRecipientId", p->wmRecipientId, indent, XMTDump);
		break;
	}
	if (p->opaqueData) DumpData(trace, "opaqueData", p->opaqueData, p->opaqueDataSize, indent, XMTDump);

	EndAttributes(trace, XMTDump, 1);
	DumpIPMPX_BaseData(_p, trace, indent, XMTDump);
	indent--;
	EndElement(trace, (_p->tag==IPMPX_AudioWatermarkingInit_Tag) ? "IPMP_AudioWatermarkingInit" : "IPMP_VideoWatermarkingInit", indent, XMTDump);
	return M4OK;
}
M4Err DumpIPMPX_SendWatermark(IPMPX_Data *_p, FILE *trace, u32 indent, Bool XMTDump)
{
	IPMPX_SendWatermark*p = (IPMPX_SendWatermark*)_p;
	StartElement(trace, (_p->tag==IPMPX_SendAudioWatermark_Tag) ? "IPMP_SendAudioWatermark" : "IPMP_SendVideoWatermark", indent, XMTDump);
	indent++;
	DumpInt(trace, "wmStatus", p->wm_status, indent, XMTDump);
	DumpInt(trace, "compression_status", p->compression_status, indent, XMTDump);
	EndAttributes(trace, XMTDump, 1);
	DumpIPMPX_BaseData(_p, trace, indent, XMTDump);
	if (p->wm_status==WM_PAYLOAD) DumpIPMPX_ByteArray(p->payload, "payload", trace, indent, XMTDump);
	if (p->opaqueData) DumpIPMPX_ByteArray(p->opaqueData, "opaqueData", trace, indent, XMTDump);
	indent--;
	EndElement(trace, (_p->tag==IPMPX_SendAudioWatermark_Tag) ? "IPMP_SendAudioWatermark" : "IPMP_SendVideoWatermark", indent, XMTDump);
	return M4OK;
}

M4Err DumpIPMPX_SelectiveDecryptionInit(IPMPX_Data *_p, FILE *trace, u32 indent, Bool XMTDump)
{
	u32 i, count;
	IPMPX_SelectiveDecryptionInit*p = (IPMPX_SelectiveDecryptionInit*)_p;
	StartElement(trace, "IPMP_SelectiveDecryptionInit", indent, XMTDump);
	indent++;
	DumpInt(trace, "mediaTypeExtension", p->mediaTypeExtension, indent, XMTDump);
	DumpInt(trace, "mediaTypeIndication", p->mediaTypeIndication, indent, XMTDump);
	DumpInt(trace, "profileLevelIndication", p->profileLevelIndication, indent, XMTDump);
	DumpInt(trace, "compliance", p->compliance, indent, XMTDump);
	if (p->RLE_Data) DumpData_16(trace, "RLE_Data", p->RLE_Data, p->RLE_DataLength, indent, XMTDump);
	EndAttributes(trace, XMTDump, 1);
	DumpIPMPX_BaseData(_p, trace, indent, XMTDump);

	count = ChainGetCount(p->SelEncBuffer);
	if (count) {
		StartList(trace, "SelectiveBuffers", indent, XMTDump);
		indent++;
		for (i=0; i<count; i++) {
			IPMPX_SelEncBuffer *sb = ChainGetEntry(p->SelEncBuffer, i);
			StartElement(trace, "IPMP_SelectiveBuffer", indent, XMTDump);
			indent++;
			DumpBin128(trace, "cipher_Id", sb->cipher_Id, indent, XMTDump);
			DumpInt(trace, "syncBoundary", sb->syncBoundary, indent, XMTDump);
			if (!sb->Stream_Cipher_Specific_Init_Info) {
				DumpInt(trace, "mode", sb->mode, indent, XMTDump);
				DumpInt(trace, "blockSize", sb->blockSize, indent, XMTDump);
				DumpInt(trace, "keySize", sb->keySize, indent, XMTDump);
			}
			EndAttributes(trace, XMTDump, 1);
			if (sb->Stream_Cipher_Specific_Init_Info) 
				DumpIPMPX_ByteArray(sb->Stream_Cipher_Specific_Init_Info, "StreamCipher", trace, indent, XMTDump);

			indent--;
			EndElement(trace, "IPMP_SelectiveBuffer", indent, XMTDump);
		}
		indent--;
		EndList(trace, "SelectiveBuffers", indent, XMTDump);
	}

	count = ChainGetCount(p->SelEncFields);
	if (!p->RLE_Data && count) {
		StartList(trace, "SelectiveFields", indent, XMTDump);
		indent++;
		for (i=0; i<count; i++) {
			IPMPX_SelEncField *sf = ChainGetEntry(p->SelEncFields, i);
			StartElement(trace, "IPMP_SelectiveField", indent, XMTDump);
			indent++;
			DumpInt(trace, "field_Id", sf->field_Id, indent, XMTDump);
			DumpInt(trace, "field_Scope", sf->field_Scope, indent, XMTDump);
			DumpInt(trace, "buf", sf->buf, indent, XMTDump);
			if (sf->mappingTable) DumpData_16(trace, "mappingTable", sf->mappingTable, sf->mappingTableSize, indent, XMTDump);
			EndAttributes(trace, XMTDump, 1);
			if (sf->shuffleSpecificInfo) 
				DumpIPMPX_ByteArray(sf->shuffleSpecificInfo, "shuffleSpecificInfo", trace, indent, XMTDump);

			indent--;
			EndElement(trace, "IPMP_SelectiveField", indent, XMTDump);
		}
		indent--;
		EndList(trace, "SelectiveFields", indent, XMTDump);
	}

	indent--;
	EndElement(trace, "IPMP_SelectiveDecryptionInit", indent, XMTDump);
	return M4OK;
}

M4Err DumpIPMPX_ISMACryp(IPMPX_Data *_p, FILE *trace, u32 indent, Bool XMTDump)
{
	IPMPX_ISMACryp*p = (IPMPX_ISMACryp*)_p;
	StartElement(trace, "ISMACryp_Data", indent, XMTDump);
	indent++;
	DumpInt(trace, "crypto_suite", p->cryptoSuite, indent, XMTDump);
	DumpInt(trace, "IV_length", p->IV_length, indent, XMTDump);
	DumpBool(trace, "selective_encryption", p->use_selective_encryption, indent, XMTDump);
	DumpInt(trace, "key_indicator_length", p->key_indicator_length, indent, XMTDump);
	EndAttributes(trace, XMTDump, 1);
	DumpIPMPX_BaseData(_p, trace, indent, XMTDump);
	indent--;
	EndElement(trace, "ISMACryp_Data", indent, XMTDump);
	return M4OK;
}

M4Err IPMPX_DumpData(IPMPX_Data *_p, FILE *trace, u32 indent, Bool XMTDump)
{
	switch (_p->tag) {
	case IPMPX_RightsData_Tag:
	case IPMPX_OpaqueData_Tag: return DumpIPMPX_OpaqueData(_p, trace, indent, XMTDump);
	case IPMPX_KeyData_Tag: return DumpIPMPX_KeyData(_p, trace, indent, XMTDump);
	case IPMPX_SecureContainer_Tag: return DumpIPMPX_SecureContainer(_p, trace, indent, XMTDump);
	case IPMPX_InitAuthentication_Tag: return DumpIPMPX_InitAuthentication(_p, trace, indent, XMTDump);
	case IPMPX_TrustSecurityMetadata_Tag: return DumpIPMPX_TrustSecurityMetadata(_p, trace, indent, XMTDump);
	case IPMPX_MutualAuthentication_Tag: return DumpIPMPX_MutualAuthentication(_p, trace, indent, XMTDump);
	case IPMPX_GetToolsResponse_Tag: return DumpIPMPX_GetToolsResponse(_p, trace, indent, XMTDump);
	case IPMPX_ParametricDescription_Tag: return DumpIPMPX_ParametricDescription(_p, trace, indent, XMTDump);
	case IPMPX_ToolParamCapabilitiesQuery_Tag: return DumpIPMPX_ToolParamCapabilitiesQuery(_p, trace, indent, XMTDump);
	case IPMPX_ToolParamCapabilitiesResponse_Tag: return DumpIPMPX_ToolParamCapabilitiesResponse(_p, trace, indent, XMTDump);
	case IPMPX_GetToolContext_Tag: return DumpIPMPX_GetToolContext(_p, trace, indent, XMTDump);
	case IPMPX_GetToolContextResponse_Tag: return DumpIPMPX_GetToolContextResponse(_p, trace, indent, XMTDump);
	case IPMPX_ConnectTool_Tag: return DumpIPMPX_ConnectTool(_p, trace, indent, XMTDump);
	case IPMPX_DisconnectTool_Tag: return DumpIPMPX_DisconnectTool(_p, trace, indent, XMTDump);
	case IPMPX_AddToolNotificationListener_Tag: return DumpIPMPX_AddToolNotificationListener(_p, trace, indent, XMTDump);
	case IPMPX_RemoveToolNotificationListener_Tag: return DumpIPMPX_RemoveToolNotificationListener(_p, trace, indent, XMTDump);
	case IPMPX_NotifyToolEvent_Tag: return DumpIPMPX_NotifyToolEvent(_p, trace, indent, XMTDump);
	case IPMPX_CanProcess_Tag: return DumpIPMPX_CanProcess(_p, trace, indent, XMTDump);
	case IPMPX_ISMACryp_Tag: return DumpIPMPX_ISMACryp(_p, trace, indent, XMTDump);
	case IPMPX_ToolAPI_Config_Tag: return DumpIPMPX_ToolAPI_Config(_p, trace, indent, XMTDump);
	case IPMPX_AudioWatermarkingInit_Tag: 
	case IPMPX_VideoWatermarkingInit_Tag: 
		return DumpIPMPX_WatermarkingInit(_p, trace, indent, XMTDump);
	case IPMPX_SendAudioWatermark_Tag: 
	case IPMPX_SendVideoWatermark_Tag: 
		return DumpIPMPX_SendWatermark(_p, trace, indent, XMTDump);
	case IPMPX_SelectiveDecryptionInit_Tag: return DumpIPMPX_SelectiveDecryptionInit(_p, trace, indent, XMTDump);

/*
	case IPMPX_UserQuery_Tag: return DumpIPMPX_UserQuery(_p, trace, indent, XMTDump);
	case IPMPX_UserQueryResponse_Tag: return DumpIPMPX_UserQueryResponse(_p, trace, indent, XMTDump);
*/
	case IPMPX_GetTools_Tag: return 0;
	default: return M4BadParam;
	}
}
