// Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies).
// All rights reserved.
// This component and the accompanying materials are made available
// under the terms of the License "Eclipse Public License v1.0"
// which accompanies this distribution, and is available
// at the URL "http://www.eclipse.org/legal/epl-v10.html".
//
// Initial Contributors:
// Nokia Corporation - initial contribution.
//
// Description:
// Symbian USBDI Descriptors Parsing Routines.
// 
//

/**
 @file
 @publishedPartner
*/

#include <d32usbdescriptors.h>
#include "usbdescutils.h"


// ----------------
// TUsbGenericDescriptor
// ----------------

EXPORT_C TUsbGenericDescriptor::TUsbGenericDescriptor()
	: iRecognisedAndParsed(EUnrecognised)
	, iNextPeer(NULL)
	, iFirstChild(NULL)
	, iParent(NULL)
	{
	}

/**
Deletes all child and peer descriptors.  Does not delete this descriptor, the caller is responsible for
doing this separately.
*/
EXPORT_C void TUsbGenericDescriptor::DestroyTree()
	{
	// Store the tree pointers
	TUsbGenericDescriptor* child = this->iFirstChild;
	TUsbGenericDescriptor* peer = this->iNextPeer;

	// Now we chop off the tree from the root node, by doing this
	// we don't need to NULL pointers as we go down (which makes
	// the iterative algorithm more efficient).
	this->iFirstChild = NULL;
	this->iNextPeer = NULL;

	// Now we walk and destroy the tree from the two pointers
	// we have
	WalkAndDelete(child);
	WalkAndDelete(peer);
	}
	
void TUsbGenericDescriptor::WalkAndDelete(TUsbGenericDescriptor* aDesc)
	{
	if(!aDesc)
		{
		return;
		}

	TUsbGenericDescriptor* topLevel = aDesc->iParent;
	do
		{
		if(aDesc->iFirstChild)
			{
			// walk down the tree depth first.
			aDesc = aDesc->iFirstChild;
			}
		else if(aDesc->iNextPeer)
			{
			// Walk along each peer at the "bottom"
			TUsbGenericDescriptor* peer = aDesc->iNextPeer;
			delete aDesc;
			aDesc = peer;
			}
		else
			{
			// End of bottom tier, so we go back up to the parent
			// and null the first child pointer so we don't go back
			// down again.
			TUsbGenericDescriptor* parent = aDesc->iParent;
			delete aDesc;
			aDesc = parent;
			if(aDesc)
				{
				aDesc->iFirstChild = NULL;
				}
			
			// if we have gone up to the top level for destruction then we don't
			// do anymore.
			if(aDesc == topLevel)
				{
				break;
				}
			}
		}
	while(aDesc);
	}

/**
Utility method to retrieve a TUint8 value from a given offset in the descriptor.
@param aOffset The offset in the binary blob at which to retrieve the value.
@return The value from the descriptor.
*/
EXPORT_C TUint8 TUsbGenericDescriptor::TUint8At(TInt aOffset) const
	{
	return ParseTUint8(iBlob, aOffset);
	}

/**
Utility method to retrieve a TUint16 value from a given offset in the descriptor.
@param aOffset The offset in the binary blob at which to retrieve the value.
@return The value from the descriptor.
*/
EXPORT_C TUint16 TUsbGenericDescriptor::TUint16At(TInt aOffset) const
	{
	return ParseTUint16(iBlob, aOffset);
	}

/**
Utility method to retrieve a TUint32 value from a given offset in the descriptor.
@param aOffset The offset in the binary blob at which to retrieve the value.
@return The value from the descriptor.
*/
EXPORT_C TUint32 TUsbGenericDescriptor::TUint32At(TInt aOffset) const
	{
	return ParseTUint32(iBlob, aOffset);
	}

/**
Assignment operator to fill in the TUsbGenericDescriptor fields from a TUsbGenericDescriptor.
Note that if a TUsbGenericDescriptor derived class has additional member fields then
they should define a specialised assignment overload for that type.
*/
EXPORT_C TUsbGenericDescriptor& TUsbGenericDescriptor::operator=(const TUsbGenericDescriptor& aDescriptor)
	{
	ibLength = aDescriptor.ibLength;
	ibDescriptorType = aDescriptor.ibDescriptorType;
	iRecognisedAndParsed = aDescriptor.iRecognisedAndParsed;
	iNextPeer = aDescriptor.iNextPeer;
	iFirstChild = aDescriptor.iFirstChild;
	iParent = aDescriptor.iParent;
	iBlob.Set(aDescriptor.iBlob);
	return *this;
	}

/**
This function determines whether the given USB descriptor is a parent
of the descriptor the method is called on.  The implementation may be
specialised for each type of descriptor to ensure the tree is correctly
built up.
@param aPotentialRelative The USB descriptor that is being queried to see if it is a parent or peer.
@return TBool Efalse if the given USB descriptor is a parent of this USB descriptor, ETrue if a peer of this descriptor
*/
/*virtual*/ TBool TUsbGenericDescriptor::IsParent(TUsbGenericDescriptor& aPotentialParent)
	{
	// As generic descriptors we consider all other "unknown" descriptors as peers, and
	// all "known" descriptors as parents of the descriptor.
	switch(aPotentialParent.ibDescriptorType)
		{
	case EDevice:
	case EConfiguration:
	case EString:
	case EInterface:
	case EEndpoint:
	case EDeviceQualifier:
	case EOtherSpeedConfiguration:
	case EInterfacePower:
	case EOTG:
	case EDebug:
	case EInterfaceAssociation:
		return ETrue;
	default:
		return EFalse;
		}
	}

/**
This function determines whether the given USB descriptor is a peer
of the descriptor the method is called on.  The implementation may be
specialised for each type of descriptor to ensure the tree is correctly
built up.
@param aPotentialPeer The USB descriptor that is being queried to see if it is a peer.
@return TBool EFalse if the given USB descriptor is a parent of this USB descriptor, ETrue if a peer of this descriptor
*/
/*virtual*/ TBool TUsbGenericDescriptor::IsPeer(TUsbGenericDescriptor& /*aPotentialPeer*/)
	{
	// As generic descriptors we are very permissive in binding peers.
	return ETrue;
	}

/**
This function determines whether the given USB descriptor is a child
of the descriptor the method is called on.  The implementation may be
specialised for each type of descriptor to ensure the tree is correctly
built up.
@param aPotentialChild The USB descriptor that is being queried to see if it is a child.
@return TBool ETrue if the given USB descriptor is a child of this USB descriptor, ETrue if a peer of this descriptor
*/
/*virtual*/ TBool TUsbGenericDescriptor::IsChild(TUsbGenericDescriptor& /*aPotentialChild*/)
	{
	// We just use the logic in the IsParent.
	return EFalse;
	}

/**
Ensures no memory is leaked if an owned TUsbGenericDescriptor is no longer needed.
@param aPtr The TUsbGenericDescriptor that is to be cleaned up.
@internalComponent
*/
EXPORT_C /*static*/ void TUsbGenericDescriptor::Cleanup(TAny* aPtr)
	{
	TUsbGenericDescriptor* ptr = static_cast<TUsbGenericDescriptor*>(aPtr);
	ptr->DestroyTree(); // belt and braces really.
	delete ptr;
	}


// ----------------------
// TUsbDeviceDescriptor
// See section 9.6.1 of the USB 2.0 specification.
// ----------------------

EXPORT_C TUsbDeviceDescriptor::TUsbDeviceDescriptor()
	{
	}

EXPORT_C /*static*/ TUsbDeviceDescriptor* TUsbDeviceDescriptor::Cast(TUsbGenericDescriptor* aOriginal)
	{
	TUsbDeviceDescriptor* ret = NULL;
	// Only cast if correctly indentified as device descriptor
	if(	aOriginal &&
		aOriginal->ibDescriptorType == EDevice &&
		aOriginal->ibLength == TUsbDeviceDescriptor::KSizeInOctets &&
		aOriginal->iRecognisedAndParsed == ERecognised)
		{
		ret = static_cast<TUsbDeviceDescriptor*>(aOriginal);
		}
	return ret;
	}

EXPORT_C TUint16 TUsbDeviceDescriptor::USBBcd() const
	{
    return ParseTUint16(iBlob, EbcdUSB);
	}
	
EXPORT_C TUint8 TUsbDeviceDescriptor::DeviceClass() const
	{
	return ParseTUint8(iBlob, EbDeviceClass);
	}

EXPORT_C TUint8 TUsbDeviceDescriptor::DeviceSubClass() const
	{
	return ParseTUint8(iBlob, EbDeviceSubClass);
	}

EXPORT_C TUint8 TUsbDeviceDescriptor::DeviceProtocol() const
	{
	return ParseTUint8(iBlob, EbDeviceProtocol);
	}

EXPORT_C TUint8 TUsbDeviceDescriptor::MaxPacketSize0() const
	{
	return ParseTUint8(iBlob, EbMaxPacketSize0);
	}

EXPORT_C TUint16 TUsbDeviceDescriptor::VendorId() const
	{
	return ParseTUint16(iBlob, EidVendor);
	}

EXPORT_C TUint16 TUsbDeviceDescriptor::ProductId() const
	{
	return ParseTUint16(iBlob, EidProduct);
	}

EXPORT_C TUint16 TUsbDeviceDescriptor::DeviceBcd() const
	{
	return ParseTUint16(iBlob, EbcdDevice);
	}

EXPORT_C TUint8 TUsbDeviceDescriptor::ManufacturerIndex() const
	{
	return ParseTUint8(iBlob, EiManufacturer);
	}

EXPORT_C TUint8 TUsbDeviceDescriptor::ProductIndex() const
	{
	return ParseTUint8(iBlob, EiProduct);
	}

EXPORT_C TUint8 TUsbDeviceDescriptor::SerialNumberIndex() const
	{
	return ParseTUint8(iBlob, EiSerialNumber);
	}

EXPORT_C TUint8 TUsbDeviceDescriptor::NumConfigurations() const
	{
	return ParseTUint8(iBlob, EbNumConfigurations);
	}

/**
The parsing routine for device descriptors.
Here the previous descriptor parameter is ignored - because logically a device descriptor can be neither a peer
nor a child.

@internalComponent
*/
/*static*/ TUsbDeviceDescriptor* TUsbDeviceDescriptor::ParseL(TPtrC8& aUsbDes, TUsbGenericDescriptor* aPreviousDesc)
	{
	TUsbDeviceDescriptor* devDes = NULL;

	const TInt KMinDeviceDesDecisionLength = 2;
	if(	aUsbDes.Length() >= KMinDeviceDesDecisionLength &&
		aUsbDes[KbDescriptorTypeOffset] == EDevice &&
		aUsbDes[KbLengthOffset] == TUsbDeviceDescriptor::KSizeInOctets)
		{
		// Robustness check - check the length field is valid, and that we have enough data.
		if(aUsbDes.Length() < TUsbDeviceDescriptor::KSizeInOctets)
			{
			User::Leave(KErrCorrupt);
			}
			
		// Robustness check - check that the device descriptor is the first to be parsed.
		if(aPreviousDesc)
			{
			User::Leave(KErrCorrupt);
			}

		// Looks ok to be a device descriptor.
		devDes = new(ELeave) TUsbDeviceDescriptor;
		// Set the standard fields
		devDes->ibLength = TUsbDeviceDescriptor::KSizeInOctets;
		devDes->ibDescriptorType = EDevice;
		// Set the blob appropriately
		devDes->iBlob.Set(aUsbDes.Left(TUsbDeviceDescriptor::KSizeInOctets));
		
		devDes->iRecognisedAndParsed = ERecognised;

		// Update the data-left-to-parse Symbian descriptor
		aUsbDes.Set(aUsbDes.Mid(TUsbDeviceDescriptor::KSizeInOctets));
		}

	return devDes;
	}

/**
@internalComponent
*/
/*virtual*/ TBool TUsbDeviceDescriptor::IsParent(TUsbGenericDescriptor& /*aPotentialParent*/)
	{
	// The device descriptor should only come by itself in a bundle, so must be top-level.
	return EFalse;
	}

/**
@internalComponent
*/
/*virtual*/ TBool TUsbDeviceDescriptor::IsPeer(TUsbGenericDescriptor& /*aPotentialPeer*/)
	{
	// The device descriptor should only come by itself in a bundle, so no other peers.
	return EFalse;
	}


// ------------------------------
// TUsbDeviceQualifierDescriptor
// See section 9.6.2 of the USB 2.0 specification.
// ------------------------------

EXPORT_C TUsbDeviceQualifierDescriptor::TUsbDeviceQualifierDescriptor()
	{
	}
	
EXPORT_C /*static*/ TUsbDeviceQualifierDescriptor* TUsbDeviceQualifierDescriptor::Cast(TUsbGenericDescriptor* aOriginal)
	{
	TUsbDeviceQualifierDescriptor* ret = NULL;
	// Only cast if correctly indentified as device qualifier descriptor
	if(	aOriginal &&
		aOriginal->ibDescriptorType == EDeviceQualifier &&
		aOriginal->ibLength == TUsbDeviceQualifierDescriptor::KSizeInOctets &&
		aOriginal->iRecognisedAndParsed == ERecognised)
		{
		ret = static_cast<TUsbDeviceQualifierDescriptor*>(aOriginal);
		}
	return ret;
	}

EXPORT_C TUint16 TUsbDeviceQualifierDescriptor::USBBcd() const
	{
	return ParseTUint16(iBlob, EbcdUSB);
	}

EXPORT_C TUint8 TUsbDeviceQualifierDescriptor::DeviceClass() const
	{
	return ParseTUint8(iBlob, EbDeviceClass);
	}

EXPORT_C TUint8 TUsbDeviceQualifierDescriptor::DeviceSubClass() const
	{
	return ParseTUint8(iBlob, EbDeviceSubClass);
	}

EXPORT_C TUint8 TUsbDeviceQualifierDescriptor::DeviceProtocol() const
	{
	return ParseTUint8(iBlob, EbDeviceProtocol);
	}

EXPORT_C TUint8 TUsbDeviceQualifierDescriptor::MaxPacketSize0() const
	{
	return ParseTUint8(iBlob, EbMaxPacketSize0);
	}

EXPORT_C TUint8 TUsbDeviceQualifierDescriptor::NumConfigurations() const
	{
	return ParseTUint8(iBlob, EbNumConfigurations);
	}

EXPORT_C TUint8 TUsbDeviceQualifierDescriptor::Reserved() const
	{
	return ParseTUint8(iBlob, EbReserved);
	}
	
/**
The parsing routine for device qualifier descriptors.

@internalComponent
*/
/*static*/ TUsbDeviceQualifierDescriptor* TUsbDeviceQualifierDescriptor::ParseL(TPtrC8& aUsbDes, TUsbGenericDescriptor* /*aPreviousDesc*/)
	{
	TUsbDeviceQualifierDescriptor* devQualDes = NULL;

	const TInt KMinDevQualDesDecisionLength = 2;
	if(	aUsbDes.Length() >= KMinDevQualDesDecisionLength &&
		aUsbDes[KbDescriptorTypeOffset] == EDeviceQualifier &&
		aUsbDes[KbLengthOffset] == TUsbDeviceQualifierDescriptor::KSizeInOctets)
		{
		// Robustness check - check the length field is valid, and that we have enough data.
		if(aUsbDes.Length() < TUsbDeviceQualifierDescriptor::KSizeInOctets)
			{
			User::Leave(KErrCorrupt);
			}

		// Looks ok to be a device quialifier descriptor.
		devQualDes = new(ELeave) TUsbDeviceQualifierDescriptor;
		// Set the standard fields
		devQualDes->ibLength = TUsbDeviceQualifierDescriptor::KSizeInOctets;
		devQualDes->ibDescriptorType = EDeviceQualifier;
		// Set the blob appropriately
		devQualDes->iBlob.Set(aUsbDes.Left(TUsbDeviceQualifierDescriptor::KSizeInOctets));

		devQualDes->iRecognisedAndParsed = ERecognised;

		// Update the data-left-to-parse Symbian descriptor
		aUsbDes.Set(aUsbDes.Mid(TUsbDeviceQualifierDescriptor::KSizeInOctets));
		}

	return devQualDes;
	}

/**
@internalComponent
*/
/*virtual*/ TBool TUsbDeviceQualifierDescriptor::IsParent(TUsbGenericDescriptor& /*aPotentialParent*/)
	{
	// Like a device descriptor, they should be top-level.
	return EFalse;
	}

/**
@internalComponent
*/
/*virtual*/ TBool TUsbDeviceQualifierDescriptor::IsPeer(TUsbGenericDescriptor& /*aPotentialPeer*/)
	{
	// Like a device descriptor, they should come by themselves.
	return EFalse;
	}


// ----------------------------
// TUsbConfigurationDescriptor
// See section 9.6.3 of the USB 2.0 specification.
// ----------------------------

EXPORT_C TUsbConfigurationDescriptor::TUsbConfigurationDescriptor()
	{
	}
	
EXPORT_C /*static*/ TUsbConfigurationDescriptor* TUsbConfigurationDescriptor::Cast(TUsbGenericDescriptor* aOriginal)
	{
	TUsbConfigurationDescriptor* ret = NULL;
	// Only cast if correctly indentified as configuration descriptor
	if(	aOriginal &&
		aOriginal->ibDescriptorType == EConfiguration &&
		aOriginal->ibLength == TUsbConfigurationDescriptor::KSizeInOctets &&
		aOriginal->iRecognisedAndParsed == ERecognised)
		{
		ret = static_cast<TUsbConfigurationDescriptor*>(aOriginal);
		}
	return ret;
	}

EXPORT_C TUint16 TUsbConfigurationDescriptor::TotalLength() const
	{
	return ParseTUint16(iBlob, EwTotalLength);
	}

EXPORT_C TUint8 TUsbConfigurationDescriptor::NumInterfaces() const
	{
	return ParseTUint8(iBlob, EbNumInterfaces);
	}

EXPORT_C TUint8 TUsbConfigurationDescriptor::ConfigurationValue() const
	{
	return ParseTUint8(iBlob, EbConfigurationValue);
	}

EXPORT_C TUint8 TUsbConfigurationDescriptor::ConfigurationIndex() const
	{
	return ParseTUint8(iBlob, EiConfiguration);
	}

EXPORT_C TUint8 TUsbConfigurationDescriptor::Attributes() const
	{
	return ParseTUint8(iBlob, EbmAttributes);
	}

EXPORT_C TUint8 TUsbConfigurationDescriptor::MaxPower() const
	{
	return ParseTUint8(iBlob, EbMaxPower);
	}

/**
The parsing routine for configuration descriptors.

@internalComponent
*/
/*static*/ TUsbConfigurationDescriptor* TUsbConfigurationDescriptor::ParseL(TPtrC8& aUsbDes, TUsbGenericDescriptor* /*aPreviousDesc*/)
	{
	TUsbConfigurationDescriptor* configDes = NULL;

	const TInt KMinConfigDesDecisionLength = 2;
	if(	aUsbDes.Length() >= KMinConfigDesDecisionLength &&
		aUsbDes[KbDescriptorTypeOffset] == EConfiguration &&
		aUsbDes[KbLengthOffset] == TUsbConfigurationDescriptor::KSizeInOctets)
		{
		// Robustness check - check the length field is valid, and that we have enough data.
		if(aUsbDes.Length() < TUsbConfigurationDescriptor::KSizeInOctets)
			{
			User::Leave(KErrCorrupt);
			}
			
		// Robustness check - check that there is sufficient data for whole bundle (wTotalLength)
		const TInt KwTotalLengthOffset = 2;
		if(aUsbDes.Length() < ParseTUint16(aUsbDes, KwTotalLengthOffset))
			{
			User::Leave(KErrCorrupt);
			}

		// Looks ok to be a configuration descriptor.
		configDes = new(ELeave) TUsbConfigurationDescriptor;
		// Set the standard fields
		configDes->ibLength = TUsbConfigurationDescriptor::KSizeInOctets;
		configDes->ibDescriptorType = EConfiguration;
		// Set the blob appropriately
		configDes->iBlob.Set(aUsbDes.Left(TUsbConfigurationDescriptor::KSizeInOctets));

		configDes->iRecognisedAndParsed = ERecognised;

		// Update the data-left-to-parse Symbian descriptor
		aUsbDes.Set(aUsbDes.Mid(TUsbConfigurationDescriptor::KSizeInOctets));
		}

	return configDes;
	}

/**
@internalComponent
*/
/*virtual*/ TBool TUsbConfigurationDescriptor::IsParent(TUsbGenericDescriptor& /*aPotentialParent*/)
	{
	// A configuration descriptor should always be the top-level descriptor in a configuration
	// bundle.
	return EFalse;
	}

/**
@internalComponent
*/
/*virtual*/ TBool TUsbConfigurationDescriptor::IsPeer(TUsbGenericDescriptor& /*aPotentialPeer*/)
	{
	// There should only ever be one configuration descriptor in a bundle.
	return EFalse;
	}


// --------------------------
// TUsbOtherSpeedDescriptor
// See section 9.6.4 of the USB 2.0 specification.
// --------------------------

EXPORT_C TUsbOtherSpeedDescriptor::TUsbOtherSpeedDescriptor()
	{
	}
	
EXPORT_C /*static*/ TUsbOtherSpeedDescriptor* TUsbOtherSpeedDescriptor::Cast(TUsbGenericDescriptor* aOriginal)
	{
	TUsbOtherSpeedDescriptor* ret = NULL;
	// Only cast if correctly indentified as other speed descriptor
	if(	aOriginal &&
		aOriginal->ibDescriptorType == EOtherSpeedConfiguration &&
		aOriginal->ibLength == TUsbOtherSpeedDescriptor::KSizeInOctets &&
		aOriginal->iRecognisedAndParsed == ERecognised)
		{
		ret = static_cast<TUsbOtherSpeedDescriptor*>(aOriginal);
		}
	return ret;
	}

EXPORT_C TUint16 TUsbOtherSpeedDescriptor::TotalLength() const
	{
	return ParseTUint16(iBlob, EwTotalLength);
	}

EXPORT_C TUint8 TUsbOtherSpeedDescriptor::NumInterfaces() const
	{
	return ParseTUint8(iBlob, EbNumInterfaces);
	}

EXPORT_C TUint8 TUsbOtherSpeedDescriptor::ConfigurationValue() const
	{
	return ParseTUint8(iBlob, EbConfigurationValue);
	}

EXPORT_C TUint8 TUsbOtherSpeedDescriptor::ConfigurationIndex() const
	{
	return ParseTUint8(iBlob, EiConfiguration);
	}

EXPORT_C TUint8 TUsbOtherSpeedDescriptor::Attributes() const
	{
	return ParseTUint8(iBlob, EbmAttributes);
	}

EXPORT_C TUint8 TUsbOtherSpeedDescriptor::MaxPower() const
	{
	return ParseTUint8(iBlob, EbMaxPower);
	}
	
/**
The parsing routine for other speed descriptors.

@internalComponent
*/
/*static*/ TUsbOtherSpeedDescriptor* TUsbOtherSpeedDescriptor::ParseL(TPtrC8& aUsbDes, TUsbGenericDescriptor* /*aPreviousDesc*/)
	{
	TUsbOtherSpeedDescriptor* oSpeedDes = NULL;

	const TInt KMinOtherSpeedDesDecisionLength = 2;
	if(	aUsbDes.Length() >= KMinOtherSpeedDesDecisionLength &&
		aUsbDes[KbDescriptorTypeOffset] == EOtherSpeedConfiguration &&
		aUsbDes[KbLengthOffset] == TUsbOtherSpeedDescriptor::KSizeInOctets)
		{
		// Robustness check - check the length field is valid, and that we have enough data.
		if(aUsbDes.Length() < TUsbOtherSpeedDescriptor::KSizeInOctets)
			{
			User::Leave(KErrCorrupt);
			}
	
		// Robustness check - check that there is sufficient data for whole bundle (wTotalLength)
		const TInt KwTotalLengthOffset = 2;
		if(aUsbDes.Length() < ParseTUint16(aUsbDes, KwTotalLengthOffset))
			{
			User::Leave(KErrCorrupt);
			}

		// Looks ok to be an other speed descriptor.
		oSpeedDes = new(ELeave) TUsbOtherSpeedDescriptor;
		// Set the standard fields
		oSpeedDes->ibLength = TUsbOtherSpeedDescriptor::KSizeInOctets;
		oSpeedDes->ibDescriptorType = EOtherSpeedConfiguration;
		// Set the blob appropriately
		oSpeedDes->iBlob.Set(aUsbDes.Left(TUsbOtherSpeedDescriptor::KSizeInOctets));

		oSpeedDes->iRecognisedAndParsed = ERecognised;

		// Update the data-left-to-parse Symbian descriptor
		aUsbDes.Set(aUsbDes.Mid(TUsbOtherSpeedDescriptor::KSizeInOctets));
		}

	return oSpeedDes;
	}

/**
@internalComponent
*/
/*virtual*/ TBool TUsbOtherSpeedDescriptor::IsParent(TUsbGenericDescriptor& /*aPotentialParent*/)
	{
	// Other speed descriptor is like a configuration descriptor, in that it should
	// not have any parents in a bundle.
	return EFalse;
	}

/**
@internalComponent
*/
/*virtual*/ TBool TUsbOtherSpeedDescriptor::IsPeer(TUsbGenericDescriptor& /*aPotentialPeer*/)
	{
	// There should only ever be one other speed descriptor in a bundle.
	return EFalse;
	}


// ------------------------------------
// TUsbInterfaceAssociationDescriptor
// See the USB IAD ECN.
// ------------------------------------

EXPORT_C TUsbInterfaceAssociationDescriptor::TUsbInterfaceAssociationDescriptor()
	{
	}
	
EXPORT_C /*static*/ TUsbInterfaceAssociationDescriptor* TUsbInterfaceAssociationDescriptor::Cast(TUsbGenericDescriptor* aOriginal)
	{
	TUsbInterfaceAssociationDescriptor* ret = NULL;
	// Only cast if correctly indentified as interface association descriptor
	if(	aOriginal &&
		aOriginal->ibDescriptorType == EInterfaceAssociation &&
		aOriginal->ibLength == TUsbInterfaceAssociationDescriptor::KSizeInOctets &&
		aOriginal->iRecognisedAndParsed == ERecognised)
		{
		ret = static_cast<TUsbInterfaceAssociationDescriptor*>(aOriginal);
		}
	return ret;
	}

EXPORT_C TUint8 TUsbInterfaceAssociationDescriptor::FirstInterface() const
	{
	return ParseTUint8(iBlob, EbFirstInterface);
	}

EXPORT_C TUint8 TUsbInterfaceAssociationDescriptor::InterfaceCount() const
	{
	return ParseTUint8(iBlob, EbInterfaceCount);
	}

EXPORT_C TUint8 TUsbInterfaceAssociationDescriptor::FunctionClass() const
	{
	return ParseTUint8(iBlob, EbFunctionClass);
	}

EXPORT_C TUint8 TUsbInterfaceAssociationDescriptor::FunctionSubClass() const
	{
	return ParseTUint8(iBlob, EbFunctionSubClass);
	}

EXPORT_C TUint8 TUsbInterfaceAssociationDescriptor::FunctionProtocol() const
	{
	return ParseTUint8(iBlob, EbFunctionProtocol);
	}

EXPORT_C TUint8 TUsbInterfaceAssociationDescriptor::FunctionIndex() const
	{
	return ParseTUint8(iBlob, EiFunction);
	}
	
/*static*/ TUsbInterfaceAssociationDescriptor* TUsbInterfaceAssociationDescriptor::ParseL(TPtrC8& aUsbDes, TUsbGenericDescriptor* /*aPreviousDesc*/)
	{
	TUsbInterfaceAssociationDescriptor* intAssocDes = NULL;

	const TInt KMinIntAssocDesDecisionLength = 2;
	if(	aUsbDes.Length() >= KMinIntAssocDesDecisionLength &&
		aUsbDes[KbDescriptorTypeOffset] == EInterfaceAssociation &&
		aUsbDes[KbLengthOffset] == TUsbInterfaceAssociationDescriptor::KSizeInOctets)
		{
		// Robustness check - check the length field is valid, and that we have enough data.
		if(aUsbDes.Length() < TUsbInterfaceAssociationDescriptor::KSizeInOctets)
			{
			User::Leave(KErrCorrupt);
			}

		// Looks ok to be a interface association descriptor.
		intAssocDes = new(ELeave) TUsbInterfaceAssociationDescriptor;
		// Set the standard fields
		intAssocDes->ibLength = TUsbInterfaceAssociationDescriptor::KSizeInOctets;
		intAssocDes->ibDescriptorType = EInterfaceAssociation;
		// Set the blob appropriately
		intAssocDes->iBlob.Set(aUsbDes.Left(TUsbInterfaceAssociationDescriptor::KSizeInOctets));
	
		intAssocDes->iRecognisedAndParsed = ERecognised;

		// Update the data-left-to-parse Symbian descriptor
		aUsbDes.Set(aUsbDes.Mid(TUsbInterfaceAssociationDescriptor::KSizeInOctets));
		}

	return intAssocDes;
	}

/**
@internalComponent
*/
/*virtual*/ TBool TUsbInterfaceAssociationDescriptor::IsParent(TUsbGenericDescriptor& aPotentialParent)
	{
	switch(aPotentialParent.ibDescriptorType)
		{
	case EConfiguration:
		return ETrue;
	case EOtherSpeedConfiguration:
		return ETrue;	// I think this should be EFalse by my reading of the USB spec - however
						// it is not explicitly clear, so play it safe.
	default:
		return EFalse;
		}
	}

/**
@internalComponent
*/
/*virtual*/ TBool TUsbInterfaceAssociationDescriptor::IsPeer(TUsbGenericDescriptor& aPotentialPeer)
	{
	switch(aPotentialPeer.ibDescriptorType)
		{
	case EInterfaceAssociation:
		return ETrue;
	case EInterface:
		// Only interfaces are peers of IADs.
			{
			TUsbInterfaceDescriptor* intDesc = TUsbInterfaceDescriptor::Cast(&aPotentialPeer);
			if(intDesc)
				{
				TInt intNum = intDesc->InterfaceNumber();
				intNum -= FirstInterface();
				if(intNum < 0 || intNum >= InterfaceCount())
					{
					// The interface number is outside the IAD region.
					return ETrue;
					}
				}
			return EFalse;
			}
	default:
		return EFalse;
		}
	}
	
/*virtual*/ TBool TUsbInterfaceAssociationDescriptor::IsChild(TUsbGenericDescriptor& aPotentialChild)
	{
	switch(aPotentialChild.ibDescriptorType)
		{
	case EInterface:
		// Only interfaces are children of IADs. And only if they are special.
			{
			TUsbInterfaceDescriptor* intDesc = TUsbInterfaceDescriptor::Cast(&aPotentialChild);
			if(intDesc)
				{
				TInt intNum = intDesc->InterfaceNumber();
				intNum -= FirstInterface();
				if(intNum >= 0 && intNum < InterfaceCount())
					{
					// The interface number is within the IAD region required.
					return ETrue;
					}
				}
			return EFalse;
			}
	default:
		return EFalse;
		}
	}


// -------------------------
// TUsbInterfaceDescriptor
// See section 9.6.5 of the USB 2.0 specification.
// -------------------------

EXPORT_C TUsbInterfaceDescriptor::TUsbInterfaceDescriptor()
	{
	}

EXPORT_C /*static*/ TUsbInterfaceDescriptor* TUsbInterfaceDescriptor::Cast(TUsbGenericDescriptor* aOriginal)
	{
	TUsbInterfaceDescriptor* ret = NULL;
	// Only cast if correctly indentified as interface descriptor
	if(	aOriginal &&
		aOriginal->ibDescriptorType == EInterface &&
		aOriginal->ibLength == TUsbInterfaceDescriptor::KSizeInOctets &&
		aOriginal->iRecognisedAndParsed == ERecognised)
		{
		ret = static_cast<TUsbInterfaceDescriptor*>(aOriginal);
		}
	return ret;
	}

EXPORT_C TUint8 TUsbInterfaceDescriptor::InterfaceNumber() const
	{
	return ParseTUint8(iBlob, EbInterfaceNumber);
	}

EXPORT_C TUint8 TUsbInterfaceDescriptor::AlternateSetting() const
	{
	return ParseTUint8(iBlob, EbAlternateSetting);
	}

EXPORT_C TUint8 TUsbInterfaceDescriptor::NumEndpoints() const
	{
	return ParseTUint8(iBlob, EbNumEndpoints);
	}

EXPORT_C TUint8 TUsbInterfaceDescriptor::InterfaceClass() const
	{
	return ParseTUint8(iBlob, EbInterfaceClass);
	}

EXPORT_C TUint8 TUsbInterfaceDescriptor::InterfaceSubClass() const
	{
	return ParseTUint8(iBlob, EbInterfaceSubClass);
	}

EXPORT_C TUint8 TUsbInterfaceDescriptor::InterfaceProtocol() const
	{
	return ParseTUint8(iBlob, EbInterfaceProtocol);
	}

EXPORT_C TUint8 TUsbInterfaceDescriptor::Interface() const
	{
	return ParseTUint8(iBlob, EiInterface);
	}
	
/**
The parsing routine for interface descriptors.

@internalComponent
*/
/*static*/ TUsbInterfaceDescriptor* TUsbInterfaceDescriptor::ParseL(TPtrC8& aUsbDes, TUsbGenericDescriptor* /*aPreviousDesc*/)
	{
	TUsbInterfaceDescriptor* intDes = NULL;

	const TInt KMinInterfaceDesDecisionLength = 2;
	if(	aUsbDes.Length() >= KMinInterfaceDesDecisionLength &&
		aUsbDes[KbDescriptorTypeOffset] == EInterface &&
		aUsbDes[KbLengthOffset] == TUsbInterfaceDescriptor::KSizeInOctets)
		{
		// Robustness check - check the length field is valid, and that we have enough data.
		if(aUsbDes.Length() < TUsbInterfaceDescriptor::KSizeInOctets)
			{
			User::Leave(KErrCorrupt);
			}

		// Looks ok to be an interface descriptor.
		intDes = new(ELeave) TUsbInterfaceDescriptor;
		// Set the standard fields
		intDes->ibLength = TUsbInterfaceDescriptor::KSizeInOctets;
		intDes->ibDescriptorType = EInterface;
		// Set the blob appropriately
		intDes->iBlob.Set(aUsbDes.Left(TUsbInterfaceDescriptor::KSizeInOctets));

		intDes->iRecognisedAndParsed = ERecognised;

		// Update the data-left-to-parse Symbian descriptor
		aUsbDes.Set(aUsbDes.Mid(TUsbInterfaceDescriptor::KSizeInOctets));
		}

	return intDes;
	}

/**
@internalComponent
*/
/*virtual*/ TBool TUsbInterfaceDescriptor::IsParent(TUsbGenericDescriptor& aPotentialParent)
	{
	switch(aPotentialParent.ibDescriptorType)
		{
	case EConfiguration:
		return ETrue;
	case EOtherSpeedConfiguration:
		return ETrue;	// I think this should be EFalse by my reading of the USB spec - however
						// it is not explicitly clear, so play it safe.
	// case EInterfaceAssociation:
	// 		We let the IAD descriptor handle the logic of how we bind to it.
	default:
		return EFalse;
		}
	}

/**
@internalComponent
*/
/*virtual*/ TBool TUsbInterfaceDescriptor::IsPeer(TUsbGenericDescriptor& aPotentialPeer)
	{
	switch(aPotentialPeer.ibDescriptorType)
		{
	//case EInterfaceAssociation:
	//		We let the IAD descriptor handle the logic of how we bind to it.
	case EInterface:
		// If another interface descriptor then it is a peer not child.
		return ETrue;
	default:
		// Any other descriptors are ignored.
		return EFalse;
		}
	}


// ------------------------
// TUsbEndpointDescriptor
// See section 9.6.6 of the USB 2.0 specification.
// ------------------------

EXPORT_C TUsbEndpointDescriptor::TUsbEndpointDescriptor()
	{
	}
	
EXPORT_C /*static*/ TUsbEndpointDescriptor* TUsbEndpointDescriptor::Cast(TUsbGenericDescriptor* aOriginal)
	{
	TUsbEndpointDescriptor* ret = NULL;
	// Only cast if correctly indentified as endpoint descriptor
	if(	aOriginal &&
		aOriginal->ibDescriptorType == EEndpoint &&
		aOriginal->ibLength == TUsbEndpointDescriptor::KSizeInOctets &&
		aOriginal->iRecognisedAndParsed == ERecognised)
		{
		ret = static_cast<TUsbEndpointDescriptor*>(aOriginal);
		}
	return ret;
	}

EXPORT_C TUint8 TUsbEndpointDescriptor::EndpointAddress() const
	{
	return ParseTUint8(iBlob, EbEndpointAddress);
	}

EXPORT_C TUint8 TUsbEndpointDescriptor::Attributes() const
	{
	return ParseTUint8(iBlob, EbmAttributes);
	}

EXPORT_C TUint16 TUsbEndpointDescriptor::MaxPacketSize() const
	{
	return ParseTUint16(iBlob, EwMaxPacketSize);
	}

EXPORT_C TUint8 TUsbEndpointDescriptor::Interval() const
	{
	return ParseTUint8(iBlob, EbInterval);
	}
	
/**
The parsing routine for endpoint descriptors.

@internalComponent
*/
/*static*/ TUsbEndpointDescriptor* TUsbEndpointDescriptor::ParseL(TPtrC8& aUsbDes, TUsbGenericDescriptor* /*aPreviousDesc*/)
	{
	TUsbEndpointDescriptor* endDes = NULL;

	const TInt KMinEndpointDesDecisionLength = 2;
	if(	aUsbDes.Length() >= KMinEndpointDesDecisionLength &&
		aUsbDes[KbDescriptorTypeOffset] == EEndpoint &&
		aUsbDes[KbLengthOffset] == TUsbEndpointDescriptor::KSizeInOctets)
		{
		// Robustness check - check the length field is valid, and that we have enough data.
		if(aUsbDes.Length() < TUsbEndpointDescriptor::KSizeInOctets)
			{
			User::Leave(KErrCorrupt);
			}

		// Looks ok to be an endpoint descriptor.
		endDes = new(ELeave) TUsbEndpointDescriptor;
		// Set the standard fields
		endDes->ibLength = TUsbEndpointDescriptor::KSizeInOctets;
		endDes->ibDescriptorType = EEndpoint;
		// Set the blob appropriately
		endDes->iBlob.Set(aUsbDes.Left(TUsbEndpointDescriptor::KSizeInOctets));

		endDes->iRecognisedAndParsed = ERecognised;

		// Update the data-left-to-parse Symbian descriptor
		aUsbDes.Set(aUsbDes.Mid(TUsbEndpointDescriptor::KSizeInOctets));
		}

	return endDes;
	}

/**
@internalComponent
*/
/*virtual*/ TBool TUsbEndpointDescriptor::IsParent(TUsbGenericDescriptor& aPotentialParent)
	{
	switch(aPotentialParent.ibDescriptorType)
		{
	case EInterface:
		return ETrue;
	default:
		return EFalse;
		}
	}

/**
@internalComponent
*/
/*virtual*/ TBool TUsbEndpointDescriptor::IsPeer(TUsbGenericDescriptor& aPotentialPeer)
	{
	switch(aPotentialPeer.ibDescriptorType)
		{
	case EEndpoint:
		return ETrue;
	default:
		return EFalse;
		}
	}

// ------------------------
// TUsbOTGDescriptor
// See section 6.4 of the USB 2.0 On-The-Go Supplement Revision 1.3
// ------------------------

EXPORT_C TUsbOTGDescriptor::TUsbOTGDescriptor()
	{
	}
	
EXPORT_C /*static*/ TUsbOTGDescriptor* TUsbOTGDescriptor::Cast(TUsbGenericDescriptor* aOriginal)
	{
	TUsbOTGDescriptor* ret = NULL;
	// Only cast if correctly indentified as otg descriptor
	if(	aOriginal &&
		aOriginal->ibDescriptorType == EOTG &&
		aOriginal->ibLength == TUsbOTGDescriptor::KSizeInOctets &&
		aOriginal->iRecognisedAndParsed == ERecognised)
		{
		ret = static_cast<TUsbOTGDescriptor*>(aOriginal);
		}
	return ret;
	}

EXPORT_C TUint8 TUsbOTGDescriptor::Attributes() const
	{
	return ParseTUint8(iBlob, EbmAttributes);
	}

EXPORT_C TBool TUsbOTGDescriptor::HNPSupported() const
    {
    return (ParseTUint8(iBlob, EbmAttributes) & 0x02) == 0x02;
    }

EXPORT_C TBool TUsbOTGDescriptor::SRPSupported() const
    {
    // Note: an illegal device (see 6.4.2 of the OTG specification) could
    // incorrectly return False for SRP and True for HNP
    // However this function just extracts the bit rather than attempting to
    // fix up a broken device.  Devices broken in this way wouldn't be expected on
    // the TPL.
    return (ParseTUint8(iBlob, EbmAttributes) & 0x01) == 0x01;
    }
	
/**
The parsing routine for OTG descriptors.

@internalComponent
*/
/*static*/ TUsbOTGDescriptor* TUsbOTGDescriptor::ParseL(TPtrC8& aUsbDes, TUsbGenericDescriptor* /*aPreviousDesc*/)
	{
	TUsbOTGDescriptor* endDes = NULL;

	const TInt KMinOTGDesDecisionLength = 2;
	if(	aUsbDes.Length() >= KMinOTGDesDecisionLength &&
		aUsbDes[KbDescriptorTypeOffset] == EOTG &&
		aUsbDes[KbLengthOffset] == TUsbOTGDescriptor::KSizeInOctets)
		{
		// Robustness check - check the length field is valid, and that we have enough data.
		if(aUsbDes.Length() < TUsbOTGDescriptor::KSizeInOctets)
			{
			User::Leave(KErrCorrupt);
			}

		// Looks ok to be an OTG descriptor.
		endDes = new(ELeave) TUsbOTGDescriptor;
		// Set the standard fields
		endDes->ibLength = TUsbOTGDescriptor::KSizeInOctets;
		endDes->ibDescriptorType = EOTG;
		// Set the blob appropriately
		endDes->iBlob.Set(aUsbDes.Left(TUsbOTGDescriptor::KSizeInOctets));

		// Null the pointers
		endDes->iFirstChild = NULL;
		endDes->iNextPeer = NULL;
		endDes->iParent = NULL;
		
		endDes->iRecognisedAndParsed = ERecognised;

		// Update the data-left-to-parse Symbian descriptor
		aUsbDes.Set(aUsbDes.Mid(TUsbOTGDescriptor::KSizeInOctets));
		}

	return endDes;
	}

/**
@internalComponent
*/
/*virtual*/ TBool TUsbOTGDescriptor::IsParent(TUsbGenericDescriptor& aPotentialParent)
	{
	switch(aPotentialParent.ibDescriptorType)
		{
	case EConfiguration:    // we are part of a configuration descriptor, or standalone
		return ETrue;
	default:
		return EFalse;
		}
	}

/**
@internalComponent
*/
/*virtual*/ TBool TUsbOTGDescriptor::IsPeer(TUsbGenericDescriptor& aPotentialPeer)
	{
    switch(aPotentialPeer.ibDescriptorType)
		{
	//case EInterfaceAssociation:
	//		We let the IAD descriptor handle the logic of how we bind to it.
	case EInterface:
		// If another interface descriptor then it is a peer not child.
		return ETrue;
	default:
		// Any other descriptors are ignored.
		return EFalse;
		}
	}


// ----------------------
// TUsbStringDescriptor
// See section 9.6.7 of the USB 2.0 specification.
// ----------------------

// The length of the header in a string descriptor (i.e. the same as every other standard USB descriptor).
static const TInt KStringDescriptorHeaderFieldLength = 2;

EXPORT_C TUsbStringDescriptor::TUsbStringDescriptor()
	{
	}
	
EXPORT_C /*static*/ TUsbStringDescriptor* TUsbStringDescriptor::Cast(TUsbGenericDescriptor* aOriginal)
	{
	TUsbStringDescriptor* ret = NULL;
	// Only cast if correctly indentified as string descriptor
	if(	aOriginal &&
		aOriginal->ibDescriptorType == EString &&
		aOriginal->ibLength >= KStringDescriptorHeaderFieldLength &&
		aOriginal->iRecognisedAndParsed == ERecognised)
		{
		ret = static_cast<TUsbStringDescriptor*>(aOriginal);
		}
	return ret;
	}

/**
For string descriptor zero, this function allows a means to iterate through the list of supported languages
for strings on this device.

@param aIndex Index into language ID table.
@return The language ID at the requested index, or KErrNotFound if the end of the list has been reached.
Note that the language IDs are unsigned 16-bit numbers, while the return from this function is signed 32-bit.
*/
EXPORT_C TInt TUsbStringDescriptor::GetLangId(TInt aIndex) const
	{
	__ASSERT_ALWAYS(aIndex >= 0, UsbDescPanic(UsbdiPanics::EUsbDescNegativeIndexToLangId));
	const TUint8 KSizeOfLangIdField = 2;

	TInt offset = KStringDescriptorHeaderFieldLength + KSizeOfLangIdField * aIndex;
	if(offset >= ibLength)
		{
		return KErrNotFound;
		}
	return ParseTUint16(iBlob, offset);
	}

/**
Writes the string data into a Symbian descriptor of sufficient size.

@param aString The Symbian descriptor that will have the string data written into it.
*/
EXPORT_C void TUsbStringDescriptor::StringData(TDes16& aString) const
	{
	const TUint8 KUnicodeCharacterWidth = 2;
	aString.Zero();

	TInt index = KStringDescriptorHeaderFieldLength;
	while(index+KUnicodeCharacterWidth <= ibLength)
		{
		aString.Append(ParseTUint16(iBlob, index));
		index += KUnicodeCharacterWidth;
		}
	}


/*static*/ TUsbStringDescriptor* TUsbStringDescriptor::ParseL(TPtrC8& aUsbDes, TUsbGenericDescriptor* /*aPreviousDesc*/)
	{
	TUsbStringDescriptor* stringDes = NULL;

	if(	aUsbDes.Length() >= KStringDescriptorHeaderFieldLength &&
		aUsbDes[KbDescriptorTypeOffset] == EString)
		{
		TUint8 stringDesLen = aUsbDes[KbLengthOffset];

		// Robustness check - check the length field is valid
		if(aUsbDes.Length() < stringDesLen || stringDesLen < KStringDescriptorHeaderFieldLength)
			{
			User::Leave(KErrCorrupt);
			}
		// Robustness check - check the length is a multiple of two.
		if(stringDesLen % 2 != 0)
			{
			User::Leave(KErrCorrupt);
			}

		// Looks ok to be a string descriptor.
		stringDes = new(ELeave) TUsbStringDescriptor;
		// Set the standard fields
		stringDes->ibLength = stringDesLen;
		stringDes->ibDescriptorType = EString;
		// Set the blob appropriately
		stringDes->iBlob.Set(aUsbDes.Left(stringDesLen));

		stringDes->iRecognisedAndParsed = ERecognised;

		// Update the data-left-to-parse Symbian descriptor
		aUsbDes.Set(aUsbDes.Mid(stringDesLen));
		}

	return stringDes;
	}

/**
@internalComponent
*/
/*virtual*/ TBool TUsbStringDescriptor::IsParent(TUsbGenericDescriptor& /*aPotentialParent*/)
	{
	// String descriptors have no parents - they are standalone.
	return EFalse;
	}

/**
@internalComponent
*/
/*virtual*/ TBool TUsbStringDescriptor::IsPeer(TUsbGenericDescriptor& /*aPotentialPeer*/)
	{
	// String descriptors have no peers - they are standalone.
	return EFalse;
	}

