/*
* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of "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.
*
* Contributors:
*
* Description: 
*
*/


#include "cdnspacket.h"
	
	
CDnsPacket::CDnsPacket(const TDes8& aPacketPtr): iPtr(aPacketPtr.Ptr()),iDataLength(aPacketPtr.Size()),
           iMaxLength(aPacketPtr.MaxSize())
	{	
	}

CDnsPacket* CDnsPacket::NewL(const TDes8& aPacketPtr)
	{
	CDnsPacket* self =  new (ELeave) CDnsPacket( aPacketPtr );	
	CleanupStack::PushL(self);
	self->ConstructL();
	CleanupStack::Pop(self);
	return self;
	}	
		
CDnsPacket::~CDnsPacket()
	{	
	}
		
void CDnsPacket::ConstructL()
	{
	iIndex = 0;
	}
	
TUint8 CDnsPacket::GetCharL()
	{
	__OOB(iIndex,iDataLength)
	TUint8 val = *(iPtr+iIndex);
	iIndex += sizeof(TUint8);		
	return val;
	}
		
TUint16 CDnsPacket::GetInt16L()
	{
	__OOB(iIndex,iDataLength)
	TUint16 val = BigEndian::Get16(iPtr+iIndex);
	iIndex += sizeof(TUint16);		
	return val;
	}
		
TUint32 CDnsPacket::GetInt32L()
	{
	__OOB(iIndex,iDataLength)
	TUint32 val = BigEndian::Get32(iPtr+iIndex);
	iIndex += sizeof(TUint32);		
	return val;
	}

const TDnsHeader& CDnsPacket::GetHeaderL()
	{
	iHeader.SetId(GetInt16L());
	iHeader.SetFlags(GetInt16L());
	iHeader.SetQueryCount(GetInt16L());
	iHeader.SetAnswerCount(GetInt16L());
	iHeader.SetAuthorityNSCount(GetInt16L());
	iHeader.SetAdditionalRCount(GetInt16L());
	
	return iHeader;
	}

void CDnsPacket::GetDomainNameL(TDes8& aName)
	{	
	TInt labelLen = GetCharL();
	RBuf8 label;
	TInt isStartingWithPointer = labelLen & KPointerBit;
	
	if(isStartingWithPointer)
	    {
		TUint16 pointerOffset = labelLen & KPointerOffsetBit;
		__OOB(pointerOffset,iDataLength)
		pointerOffset = (pointerOffset << 8) + GetCharL();
		GetDomainNameAtIndexL(aName, pointerOffset);			
	    }
	else
		{
		while(labelLen)
			{			
			TInt isPointer = labelLen & KPointerBit;			
			if(isPointer)
				{
				TUint16 pointerOffset = labelLen & KPointerOffsetBit;
				__OOB(pointerOffset,iDataLength)
				pointerOffset = (pointerOffset << 8) + GetCharL();
				label.CreateL(KMaxDNSNameLength);
				GetStringAtIndexL(label,pointerOffset);		
				}
			else
				{
				label.CreateL(labelLen);
				GetStringL(label,labelLen);
				}			
			aName.Append(label);
            if(aName[aName.Size()-1]!='.')
                aName.Append(KDot);
			label.Close();
			if(isPointer )
				{
				break;
				}
			else
				{
				labelLen = GetCharL();		
				}			
			}
		}		
	}
	
void CDnsPacket::GetRdDomainNameL(TDes8& aDomainName,TUint aLength)
	{	
	TInt labelLen = GetCharL();
	aLength--;
	RBuf8 label;
	TInt isStartingWithPointer = labelLen & KPointerBit;
	
	while(aLength)
		{		
		TInt isPointer = labelLen & KPointerBit;	
		if(isPointer)
			{
			TUint16 pointerOffset = labelLen & KPointerOffsetBit;
			__OOB(pointerOffset,iDataLength)
			pointerOffset = (pointerOffset << 8) + GetCharL();
			aLength--;
			label.CreateL(KMaxLabelLength);
			if(isStartingWithPointer )  
				{
				GetDomainNameAtIndexL(aDomainName, pointerOffset);
				}
			else
				{
				GetDomainNameAtIndexL(label, pointerOffset);
				//GetStringAtIndexL(label, pointerOffset);				
				}
			}
		else
			{
			label.CreateL(labelLen);
			GetStringL(label,labelLen);
			aLength-=labelLen;
			}
			
		aDomainName.Append(label);
		label.Close();
		if(isStartingWithPointer)
			{
			break;
			}
		else
			{
			if(aLength )
				{
				labelLen = GetCharL();
				aLength--;
                if(aDomainName[aDomainName.Size()-1]!='.')
                    aDomainName.Append(KDot);
				}
			}
		}
	}

void CDnsPacket::GetStringL(TDes8& aString, TUint16 aLength)	
	{
	__OOB(iIndex,iDataLength)
	aString.Copy(iPtr+iIndex,aLength);
	iIndex+= aLength;
	}

void CDnsPacket::GetDomainNameAtIndexL(TDes8& aDomainName, TUint aOffset)
	{
	__OOB(aOffset,iDataLength)
	TUint8 labelLen = *(iPtr + aOffset);
	RBuf8 label;
	TInt isPointer;
	TUint16 pointerOffset;
	TInt isStartingWithPointer = labelLen & KPointerBit;
	TUint8 ptrPos;
	if(isStartingWithPointer)
		{
		pointerOffset = labelLen & KPointerOffsetBit;
		__OOB(aOffset,iDataLength)
		aOffset++;
		ptrPos = *(iPtr + aOffset);
		pointerOffset = (pointerOffset << 8) + ptrPos;		
		GetDomainNameAtIndexL(aDomainName, pointerOffset);
		}
	else
		{
		while(labelLen)		
			{
			label.CreateL(KMaxLabelLength);
			GetStringAtIndexL(label, aOffset);
			aDomainName.Append(label);
            if(aDomainName[aDomainName.Size()-1]!='.')
                aDomainName.Append(KDot);
			__OOB(aOffset,iDataLength)
			aOffset++; // increment by one byte for length field
			aOffset += labelLen;
			label.Close();	
			labelLen = 	*(iPtr + aOffset);
			isPointer = labelLen & KPointerBit;
			if(isPointer)
				{
				pointerOffset = labelLen & KPointerOffsetBit;
				__OOB(aOffset,iDataLength)
				aOffset++;
				ptrPos = *(iPtr + aOffset);
				pointerOffset = (pointerOffset << 8) + ptrPos;			
				label.CreateL(KMaxLabelLength);
				GetStringAtIndexL(label, pointerOffset);				
				aDomainName.Append(label);
				if(aDomainName[aDomainName.Size()-1]!='.')
				    aDomainName.Append(KDot);
				label.Close();
				break;
				}
			}
		}	
	}
		
void CDnsPacket::GetStringAtIndexL(TDes8& aLabel, TUint aOffset)
	{
	__OOB(aOffset,iDataLength)
	TUint8 labelLen = *(iPtr + aOffset);
	if(labelLen & KPointerBit)		// recursive pointers
		{
		TUint16 pointerOffset = labelLen & KPointerOffsetBit;
		pointerOffset = (pointerOffset << 8) + GetCharL();
		GetStringAtIndexL(aLabel, pointerOffset);
		}
	else
		{
		aLabel.Copy(iPtr+aOffset+1, labelLen);			
		}
	}
