//Editor-Info: -*- C++ -*-
//
//Subject: TOVE project / testing/testadapter/uni
//
//File: unipducoder.cpp
//
//Version: $Revision: 1.17 $
//
//State: $State: Exp $
//
//Date: $Date: 1999/01/21 13:06:50 $
//
//Organisation:
//      Helsinki University of Technology
//      Laboratory of Telecommunications Software and Multimedia
//
//Author:
//      Timo Kokkonen
//      Jussi Turunen
//
//Description:
//      See corresponding header file.
//
//Copyright:
//      Copyright 1999 Helsinki University of Technology
//      ALL RIGHTS RESERVED BETWEEN JANUARY 1996 AND JUNE 1999.
//
//Licence:
//
//
//History:
//
//
#include <typeinfo>
#include <string>

#include "pf/debug.h"
#include "pf/exception.h"
#include "pf/bytes.h"
#include "pf/error.h"
#include "unicoderstrings.h"
#include "unipducoder.h"

uniPDUcoder :: uniPDUcoder(void)
    : pduCoderBase(),
      SHIFTFORPDUTYPE(5),
      _IElengthInBits(0),
      _extensionBit(1)
{
    return;
}

uniPDUcoder :: ~uniPDUcoder(void)
{
    return;
}

//----------------------------------------------------------------------

//
//Function: decode
//
//Description:
//      A general decode method for UNI PDUs. Uses the same structure as
//      UNI protocol in decoding: PDU type is read first and decoding
//      is done with decodeHeader()- an decodeIEs()-method regardless
//      of the actual PDU type. This is because PDU type doesn't have
//      anything to do with the IE types and the header structure.
//      PDU name is stored for use in sending a decoded SM to the tester.
//

otMessage::SerializedMessage uniPDUcoder :: decode(const pfFrame &frame_)
{
    try
    {
        frameToDataBuffer(frame_);

        // if _databuffer is too short to read pdu's type.
        if (_dataBuffer.length() < (SHIFTFORPDUTYPE * OCTETSIZE))
        {
            unknownPdu();
            return _message;
        }

        pfUlong pduType = 
            _dataBuffer.readBits((SHIFTFORPDUTYPE * OCTETSIZE), 8);

        switch (pduType)
        {
            case B0000_0001: // Alerting
                debugString("Found new PDU", ALERTStr);
                storePDUname(ALERTStr);
                decodeHeader();
                decodeIEs();
		break;
            case B0000_0010: // Call proceeding
                debugString("Found new PDU", CALL_PROCStr);
                storePDUname(CALL_PROCStr);
                decodeHeader();
                decodeIEs();
		break;
            case B0000_0101: // Setup
                debugString("Found new PDU", SETUPStr);
                storePDUname(SETUPStr);
                decodeHeader();
                decodeIEs();
		break;
            case B0000_0111: // Connect
                debugString("Found new PDU", CONNStr);
                storePDUname(CONNStr);
                decodeHeader();
                decodeIEs();
		break;
            case B0000_1111: // Connect acknowledge
                debugString("Found new PDU", CONN_ACKStr);
                storePDUname(CONN_ACKStr);
                decodeHeader();
                decodeIEs();
		break;
            case B0100_0110: // Restart
                debugString("Found new PDU", RESTStr);
                storePDUname(RESTStr);
                decodeHeader();
                decodeIEs();
		break;
            case B0100_1101: // Release
                debugString("Found new PDU", REL_REPStr);
                storePDUname(REL_REPStr);
                decodeHeader();
                decodeIEs();
		break;
            case B0100_1110: // Restart acknowledge
                debugString("Found new PDU", REST_ACKStr);
                storePDUname(REST_ACKStr);
                decodeHeader();
                decodeIEs();
		break;
            case B0101_1010: // Release complete
                debugString("Found new PDU", REL_COM_REPStr);
                storePDUname(REL_COM_REPStr);
                decodeHeader();
                decodeIEs();
		break;
            case B0111_1101: // Status
                debugString("Found new PDU", STATStr);
                storePDUname(STATStr);
                decodeHeader();
                decodeIEs();
		break;
            case B0111_0101: // Status enquiry
                debugString("Found new PDU", STAT_ENQStr);
                storePDUname(STAT_ENQStr);
                decodeHeader();
                decodeIEs();
		break;
            // The PDU's are not implemented in tester
            case B1000_0000: // Add party
                printWarningMsg(
                    "Multipoint properties, Add party pdu found");
            case B1000_0001: // Add party acknowledge
                printWarningMsg(
                    "Multipoint properties, Add party acknowledge pdu found");
            case B1000_0010: // Add party reject
                printWarningMsg(
                    "Multipoint properties, Add party reject pdu found");
            case B1000_0011: // Drop party
                printWarningMsg(
                    "Multipoint properties, Drop party pdu found");
            case B1000_0100: // Drop party acknowledge
                printWarningMsg(
                    "Multipoint properties, Drop party acknowledge pdu found");
            default:
                unknownPdu();
                break;
        }
    }
    catch (pfException &except)
    {
        string name = except.getName();
        printWarningMsg(name + " exception caught");
    }

    // If _dataBuffer still contains some data it is stored into 
    // UnknownField. This data is "extra" data and the the way to
    // handle it is this.
    storeUnknownField(_dataBuffer.length());

    return _message;
}

//----------------------------------------------------------------------

//
//Function: decodeHeader
//
//Description:
//      Decodes UNI PDU header
//
// Type          Length   Name
// Octetstring   1        Protocol Discriminator
// Bitstring     4        Bits 5 to 8
// Bitstring     4        CR length
// Bitstring     1        Flag
// Bitstring     23       CR value
// Octetstring   1        Identifier
// Bitstring     1        Extension bit
// Bitstring     2        Coding Standard
// Bitstring     1        Flag
// Bitstring     2        Spare
// Bitstring     2        IE Action Indicator
// Octetstring   2        Length of the message
//
void uniPDUcoder :: decodeHeader(void)
{
    debugUser("Decoding PDU header");

    if ((_dataBuffer.length() % OCTETSIZE) != 0)
    {
        printErrorMsg(
            "DataBuffer length not 8-bit aligned in the beginning of IE");
    }
    
    decodeOctetString(PDStr, 1);

    decodeBegOfElement("CR");      // Begin CR
    decodeBegOfElement("CR_1");
    decodeBitString(CR_1_85Str, 4);
    decodeBitString(CR_1_41Str, 4);
    decodeEndOfElement("CR_1");

    decodeBegOfElement("CR_234");
    decodeBitString(CR_234_8Str, 1);
    decodeBitString(CR_234_RStr, 23);
    decodeEndOfElement("CR_234");
    decodeEndOfElement("CR");      // End CR

    decodeBegOfElement("MT");      // Begin MT

    decodeOctetString(MT_1Str, 1);

    decodeBegOfElement("MT_2");
    getExtension();
    decodeBitString(MT_2_8Str, 1);
    decodeBitString(MT_2_76Str, 2);
    decodeBitString(MT_2_5Str, 1);
    decodeBitString(MT_2_43Str, 2);
    decodeBitString(MT_2_21Str, 2);
    endExtension();
    decodeEndOfElement("MT_2");
    decodeEndOfElement("MT");      // End MT

    decodeBegOfElement("ML");      // Begin ML
    decodeOctetString(ML_12Str, 2);
    decodeEndOfElement("ML");      // End ML

    return;
}

//----------------------------------------------------------------------

//
//Function: unknownPdu
//
//Description:
//      PDU type wasn't recognized. This method passes all of the received 
//      data to the tester in one field.
//
void uniPDUcoder :: unknownPdu(void)
{
    printWarningMsg(UNKNOWN_PDUStr);

    storeUnknownField(_dataBuffer.length());

    return;
}

//----------------------------------------------------------------------

//
//Function: decodeIEs
//
//Description:
//      Decodes all UNI IE's from _dataBuffer
//

void uniPDUcoder :: decodeIEs(void)
{
    pfUlong IEtype;
    // number of ca_ie's in the decoded PDU.
    pfUlong numberOfCAIEs = 1;

    debugUser("Decoding IE's ...");

    while ( _dataBuffer.length() >= OCTETSIZE)
    {
        if ((_dataBuffer.length() % OCTETSIZE) != 0)
        {
            printErrorMsg(
                "DataBuffer length not 8-bit aligned in the beginning of IE");
        }

        IEtype = _dataBuffer.readBits(0, OCTETSIZE);

        switch (IEtype)
        {
            case B0000_1000: // Cause
                decodeCA_IE(numberOfCAIEs);
                numberOfCAIEs++;
                break;
            case B0001_0100: // Call state
                decodeCS_IE();
                break;
            case B0101_1000: // ATM adaptation layer parameters
                decodeAAL_IE();
                break;
            case B0101_1001: // ATM traffic descriptor
                decodeATD_IE();
                break;
            case B0101_1010: // Connection identifier
                decodeCI_IE();
                break;
            case B0101_1100: // Quality of service parameter
                decodeQOS_IE();
                break;
            case B0101_1101: // Broadband high layer information
                decodeBHL_IE();
                break;
            case B0101_1110: // Broadband bearer capability
                decodeBBC_IE();
                break;
            case B0101_1111: // Broadband low-layer information
                decodeBLL_IE();
                break;
            case B0110_0000: // Broadband locking shift
                decodeBLSH_IE();
                break;
            case B0110_0001: // Broadband non-locking shift
                decodeBNSH_IE();
                break;
            case B0110_0010: // Broadband sending complete
                decodeBSC_IE();
                break;
            case B0110_0011: // Broadband repeat indicator
                decodeBRI_IE();
                break;
            case B0110_1100: // Calling party number
                decodeCGN_IE();
                break;
            case B0110_1101: // Calling party subaddress
                decodeCGS_IE();
                break;
            case B0111_0000: // Called party number
                decodeCDN_IE();
                break;
            case B0111_0001: // Called party subaddress
                decodeCDS_IE();
                break;
            case B0111_1000: // Transit network selection
                decodeTNS_IE();
                break;
            case B0111_1001: // Restart indicator
                decodeRI_IE();
                break;
            // The IE's are not implemented in tester
            case B0101_0100: // Endpoint reference
                printWarningMsg(
                    "Multipoint properties, Endpoint reference ie found");
            case B0101_0101: // Endpoint state
                printWarningMsg(
                    "Multipoint properties, Endpoint state ie found");
            default:
                decodeUN_IE(); // Unknown IE
                break;
        }
    }

    return;
}

//----------------------------------------------------------------------

//
//Function: decodeCA_IE
//
//Description:
//      Decodes UNI Cause IE
//
// Type          Length   Name
// Octetstring   1        Identifier
// Bitstring     1        Extension bit
// Bitstring     2        Coding Standard
// Bitstring     5        IE Instruction Field
// Octetstring   2        Length of IE
// Bitstring     1        Extension bit
// Bitstring     3        Spare bits
// Bitstring     4        Location
// Bitstring     8        Cause value
// Hexstring     n        Diagnostic(s)
//
void uniPDUcoder :: decodeCA_IE(pfUlong numberOfCAIEs_)
{
    debugUser("Decoding CA IE");
    
    string ca_ie("CA_OCC");
    addUlongToString(ca_ie, numberOfCAIEs_);
    decodeBegOfElement(ca_ie);       // Begin CA

    decodeOctetString(CA_1Str, 1);
    
    decodeBegOfElement("CA_2");       // Begin CA_2
    getExtension();
    decodeBitString(CA_2_8Str, 1);
    decodeBitString(CA_2_76Str, 2);
    decodeBitString(CA_2_51Str, 5);
    endExtension();
    decodeEndOfElement("CA_2");       // End CA_2

    getIElength();
    decodeOctetString(CA_34Str, 2);

    decodeBegOfElement("CA_5");       // Begin CA_5
    getExtension();
    decodeBitStr(CA_5_8Str, 1);
    decodeBitStr(CA_5_75Str, 3);
    decodeBitStr(CA_5_41Str, 4);
    pfUlong tmp = endExtension();
    decodeEndOfElement("CA_5");       // End CA_5
    decreaseIElength(tmp*OCTETSIZE);

    decodeBitStr(CA_6Str, 8);

    // The diagnostics field. Usually contains no data.
    // Should find a "neater" error message than "_dataBuffer
    // empty." .
    decodeHexStr(CA_7Str, blocksInIE(HEXSIZE));

    decodeEndOfElement(ca_ie);       // End CA

    return;
}

//----------------------------------------------------------------------

//
//Function: decodeCS_IE
//
//Description:
//      Decodes UNI Call state IE
//
// Type          Length   Name
// Octetstring   1        Identifier
// Bitstring     1        Extension bit
// Bitstring     2        Coding Standard
// Bitstring     5        IE Instruction Field
// Octetstring   2        Length of IE
// Bitstring     2        Spare bits
// Bitstring     6        Call State value
//
void uniPDUcoder :: decodeCS_IE(void)
{
    debugUser("Decoding CS IE");

    decodeBegOfElement("CS");       // Begin CS
    decodeOctetString(CS_1Str, 1);
    
    decodeBegOfElement("CS_2");     // Begin CS_2
    getExtension();
    decodeBitString(CS_2_8Str, 1);
    decodeBitString(CS_2_76Str, 2);
    decodeBitString(CS_2_51Str, 5);
    endExtension();
    decodeEndOfElement("CS_2");     // End CS_2

    getIElength();
    decodeOctetString(CS_34Str, 2);

    decodeBegOfElement("CS_5");     // Begin CS_5
    decodeBitStr(CS_5_87Str, 2);
    decodeBitStr(CS_5_61Str, 6);
    decodeEndOfElement("CS_5");     // End CS_5

    // if there is some extra data in ie
    storeUnknownField(_IElengthInBits);
    decodeEndOfElement("CS");       // End CS

    return;
}

//----------------------------------------------------------------------

//
//Function: decodeAAL_IE
//
//Description:
//      Decodes UNI ATM adaptation layer parameters IE
//
// Type          Length   Name
// Octetstring   1        Identifier
// Bitstring     1        Extension bit
// Bitstring     2        Coding Standard
// Bitstring     5        IE Instruction Field
// Octetstring   2        Length of IE
// Bitstring     8        AAL Type
// Hexstring     n        AAL parameters Information
//
void uniPDUcoder :: decodeAAL_IE(void)
{
    debugUser("Decoding AAL IE");

    decodeBegOfElement("AAL");       // Begin AAL

    decodeOctetString(AAL_1Str, 1);
    
    decodeBegOfElement("AAL_2");     // Begin AAL_2
    getExtension();
    decodeBitString(AAL_2_8Str, 1);
    decodeBitString(AAL_2_76Str, 2);
    decodeBitString(AAL_2_51Str, 5);
    endExtension();
    decodeEndOfElement("AAL_2");     // End AAL_2

    getIElength();
    decodeOctetString(AAL_34Str, 2);

    decodeBitStr(AAL_5Str, 8);
    decodeHexStr(AAL_RStr, blocksInIE(HEXSIZE));
    decodeEndOfElement("AAL");       // End AAL

    return;
}

//----------------------------------------------------------------------

//
//Function: decodeATD_IE
//
//Description:
//      Decodes UNI ATM traffic descriptor IE
//
// Type          Length   Name
// Octetstring   1        Identifier
// Bitstring     1        Extension bit
// Bitstring     2        Coding Standard
// Bitstring     5        IE Instruction Field
// Octetstring   2        Length of IE
// Octetstring   1        Forward Peak Cell Rate Id (CLP=0)
// Octetstring   3        Forward Peak Cell Rate
// Octetstring   1        Backward Peak Cell Rate Id (CLP=0)
// Octetstring   3        Backward Peak Cell Rate
// Octetstring   1        Forward Peak Cell Rate Id (CLP=0+1)
// Octetstring   3        Forward Peak Cell Rate
// Octetstring   1        Backward Peak Cell Rate Id (CLP=0+1)
// Octetstring   3        Backward Peak Cell Rate
// Octetstring   1        Forward Sustainable Cell Rate Id (CLP=0)
// Octetstring   3        Forward Sustainable Cell Rate
// Octetstring   1        Backward Sustainable Cell Rate Id (CLP=0)
// Octetstring   3        Backward Sustainable Cell Rate
// Octetstring   1        Forward Sustainable Cell Rate Id (CLP=0+1)
// Octetstring   3        Forward Sustainable Cell Rate
// Octetstring   1        Backward Sustainable Cell Rate Id (CLP=0+1)
// Octetstring   3        Backward Sustainable Cell Rate
// Octetstring   1        Forward Maximum Burst Size Id (CLP=0)
// Octetstring   3        Forward Maximum Burst Size
// Octetstring   1        Backward Maximum Burst Size Id (CLP=0)
// Octetstring   3        Backward Maximum Burst Size
// Octetstring   1        Forward Maximum Burst Size Id (CLP=0+1)
// Octetstring   3        Forward Maximum Burst Size
// Octetstring   1        Backward Maximum Burst Size Id (CLP=0+1)
// Octetstring   3        Backward Maximum Burst Size
// Octetstring   1        Best Effort Indicator
// Octetstring   1        Traffic Management Options Identifier
// Bitstring     6        Spare bits
// Bitstring     1        Tagging Backward
// Bitstring     1        Tagging Forward
//
void uniPDUcoder :: decodeATD_IE(void)
{
    debugUser("Decoding ATD IE");

    decodeBegOfElement("ATD");       // Begin ATD

    decodeOctetString(ATD_1Str, 1);
    
    decodeBegOfElement("ATD_2");       // Begin ATD_2
    getExtension();
    decodeBitString(ATD_2_8Str, 1);
    decodeBitString(ATD_2_76Str, 2);
    decodeBitString(ATD_2_51Str, 5);
    endExtension();
    decodeEndOfElement("ATD_2");       // End ATD_2

    getIElength();
    decodeOctetString(ATD_34Str, 2);

    pfUlong identifier;

    // This case-hack is because parameters are position independent.
    // See UNI3.1 Sec.5 Chap. 5.4.5.6 (Page 203).
    while (_IElengthInBits >= OCTETSIZE)
    {
        identifier = _dataBuffer.readBits(0, OCTETSIZE);

        switch (identifier)
        {
            case B1000_0010: // Forward Peak Cell Rate Id (CLP=0)
                decodeOctetStr(ATD_5Str, 1);
                decodeOctetStr(ATD_5_1_2_3Str, 3);                
                break;
            case B1000_0011: // Backward Peak Cell Rate Id (CLP=0)
                decodeOctetStr(ATD_6Str, 1);
                decodeOctetStr(ATD_6_1_2_3Str, 3);                
                break;
            case B1000_0100: // Forward Peak Cell Rate Id (CLP=0+1)
                decodeOctetStr(ATD_7Str, 1);
                decodeOctetStr(ATD_7_1_2_3Str, 3);                
                break;
            case B1000_0101: // Backward Peak Cell Rate Id (CLP=0+1)
                decodeOctetStr(ATD_8Str, 1);
                decodeOctetStr(ATD_8_1_2_3Str, 3);                
                break;
            case B1000_1000: // Forward Sustainable Cell Rate Id (CLP=0)
                decodeOctetStr(ATD_9Str, 1);
                decodeOctetStr(ATD_9_1_2_3Str, 3);                
                break;
            case B1000_1001: // Backward Sustainable Cell Rate Id (CLP=0)
                decodeOctetStr(ATD_10Str, 1);
                decodeOctetStr(ATD_10_1_2_3Str, 3);                
                break;
            case B1001_0000: // Forward Sustainable Cell Rate Id (CLP=0+1)
                decodeOctetStr(ATD_11Str, 1);
                decodeOctetStr(ATD_11_1_2_3Str, 3);                
                break;
            case B1001_0001: // Backward Sustainable Cell Rate Id (CLP=0+1)
                decodeOctetStr(ATD_12Str, 1);
                decodeOctetStr(ATD_12_1_2_3Str, 3);                
                break;
            case B1010_0000: // Forward Maximum Burst Size Id (CLP=0)
                decodeOctetStr(ATD_13Str, 1);
                decodeOctetStr(ATD_13_1_2_3Str, 3);                
                break;
            case B1010_0001: // Backward Maximum Burst Size Id (CLP=0)
                decodeOctetStr(ATD_14Str, 1);
                decodeOctetStr(ATD_14_1_2_3Str, 3);                
                break;
            case B1011_0000: // Forward Maximum Burst Size Id (CLP=0+1)
                decodeOctetStr(ATD_15Str, 1);
                decodeOctetStr(ATD_15_1_2_3Str, 3);                
                break;
            case B1011_0001: // Backward Maximum Burst Size Id (CLP=0+1)
                decodeOctetStr(ATD_16Str, 1);
                decodeOctetStr(ATD_16_1_2_3Str, 3);                
                break;
            case B1011_1110: // Best Effort Indicator
                decodeOctetStr(ATD_17Str, 1);
                break;
            case B1011_1111: // Traffic Management Options Identifier
                decodeOctetStr(ATD_18Str, 1);
                decodeBegOfElement("ATD_18_1");       // Begin ATD_18_1
                decodeBitStr(ATD_18_1_83Str, 6);
                decodeBitStr(ATD_18_1_2Str, 1);
                decodeBitStr(ATD_18_1_1Str, 1);
                decodeEndOfElement("ATD_18_1");       // End ATD_18_1
                break;
            default:
                storeUnknownField(_IElengthInBits);
                break;
        }
    }

    // if there is some extra data in ie
    storeUnknownField(_IElengthInBits);

    decodeEndOfElement("ATD");       // End ATD
    return;
}

//----------------------------------------------------------------------

//
//Function: decodeCI_IE
//
//Description:
//      Decodes UNI Connection identifier IE
//
// Type          Length   Name
// Octetstring   1        Identifier
// Bitstring     1        Extension bit
// Bitstring     2        Coding Standard
// Bitstring     5        IE Instruction Field
// Octetstring   2        Length of IE
// Bitstring     1        Extension bit
// Bitstring     2        Spare bits
// Bitstring     2        VP Associated Signaling
// Bitstring     3        Preferred/Exclusive
// Octetstring   2        Virtual Path Connection Identifier
// Octetstring   2        Virtual Channel Identifer
//
void uniPDUcoder :: decodeCI_IE(void)
{
    debugUser("Decoding CI IE");

    decodeBegOfElement("CI");       // Begin CI

    decodeOctetString(CI_1Str, 1);
    
    decodeBegOfElement("CI_2");     // Begin CI_2
    getExtension();
    decodeBitString(CI_2_8Str, 1);
    decodeBitString(CI_2_76Str, 2);
    decodeBitString(CI_2_51Str, 5);
    endExtension();
    decodeEndOfElement("CI");       // End CI_2

    getIElength();
    decodeOctetString(CI_34Str, 2);

    decodeBegOfElement("CI_5");       // Begin CI_5
    getExtension();
    decodeBitStr(CI_5_8Str, 1);
    decodeBitStr(CI_5_76Str, 2);
    decodeBitStr(CI_5_54Str, 2);
    decodeBitStr(CI_5_31Str, 3);
    pfUlong tmp = endExtension();
    decreaseIElength(tmp*OCTETSIZE);
    decodeEndOfElement("CI_5");       // End CI_5

    decodeOctetStr(CI_67Str, 2);
    decodeOctetStr(CI_89Str, 2);

    // if there is some extra data in ie
    storeUnknownField(_IElengthInBits);

    decodeEndOfElement("CI");       // End CI

    return;
}

//----------------------------------------------------------------------

//
//Function: decodeQOS_IE
//
//Description:
//      Decodes UNI Quality of service parameter IE
//
// Type          Length   Name
// Octetstring   1        Identifier
// Bitstring     1        Extension bit
// Bitstring     2        Coding Standard
// Bitstring     5        IE Instruction Field
// Octetstring   2        Length of IE
// Bitstring     8        Qos Class Forward
// Bitstring     8        Qos Class Backward
//
void uniPDUcoder :: decodeQOS_IE(void)
{
    debugUser("Decoding QOS IE");

    decodeBegOfElement("QOS");       // Begin QOS
 
    decodeOctetString(QOS_1Str, 1);
    
    decodeBegOfElement("QOS_2");       // Begin QOS_2
    getExtension();
    decodeBitString(QOS_2_8Str, 1);
    decodeBitString(QOS_2_76Str, 2);
    decodeBitString(QOS_2_51Str, 5);
    endExtension();
    decodeEndOfElement("QOS_2");       // End QOS_2

    getIElength();
    decodeOctetString(QOS_34Str, 2);

    decodeBitStr(QOS_5Str, 8);
    decodeBitStr(QOS_6Str, 8);

    // if there is some extra data in ie
    storeUnknownField(_IElengthInBits);

    decodeEndOfElement("QOS");       // End QOS

    return;
}

//----------------------------------------------------------------------

//
//Function: decodeBHL_IE
//
//Description:
//      Decodes UNI Broadband high layer information IE
//
// Type          Length   Name
// Octetstring   1        Identifier
// Bitstring     1        Extension bit
// Bitstring     2        Coding Standard
// Bitstring     5        IE Instruction Field
// Octetstring   2        Length of IE
// Bitstring     1        Extension bit
// Bitstring     7        High Layer Information Type
// Hexstring     n        High Layer Information
//
void uniPDUcoder :: decodeBHL_IE(void)
{
    debugUser("Decoding BHL IE");
    
    decodeBegOfElement("BHL");       // Begin BHL

    decodeOctetString(BHL_1Str, 1);
    
    decodeBegOfElement("BHL_2");       // Begin BHL_2
    getExtension();
    decodeBitString(BHL_2_8Str, 1);
    decodeBitString(BHL_2_76Str, 2);
    decodeBitString(BHL_2_51Str, 5);
    endExtension();
    decodeEndOfElement("BHL_2");       // End BHL_2

    getIElength();
    decodeOctetString(BHL_34Str, 2);

    decodeBegOfElement("BHL_5");       // Begin BHL_5
    getExtension();
    decodeBitStr(BHL_5_8Str, 1);
    decodeBitStr(BHL_5_71Str, 7);
    pfUlong tmp = endExtension();
    decreaseIElength(tmp*OCTETSIZE);
    decodeEndOfElement("BHL_5");       // End BHL_5

    decodeHexStr(BHL_RStr, blocksInIE(HEXSIZE));

    decodeEndOfElement("BHL");       // End BHL

    return;
}

//----------------------------------------------------------------------

//
//Function: decodeBBC_IE
//
//Description:
//      Decodes UNI Broadband bearer capability IE
//
// Type          Length   Name
// Octetstring   1        Identifier
// Bitstring     1        Extension bit
// Bitstring     2        Coding Standard
// Bitstring     5        IE Instruction Field
// Octetstring   2        Length of IE
// Bitstring     1        Extension bit
// Bitstring     2        Spare bits
// Bitstring     5        Bearer Class
// Bitstring     1        Extension bit
// Bitstring     2        Spare bits
// Bitstring     3        Traffic Type
// Bitstring     2        Timing Requirements
// Bitstring     1        Extension bit
// Bitstring     2        Susceptibility to Clipping
// Bitstring     3        Spare bits
// Bitstring     2        User Plane Connection Configuration
//
void uniPDUcoder :: decodeBBC_IE(void)
{
    debugUser("Decoding BBC IE");

    decodeBegOfElement("BBC");       // Begin BBC
    decodeOctetString(BBC_1Str, 1);

    decodeBegOfElement("BBC_2");       // Begin BBC_2
    getExtension();
    decodeBitString(BBC_2_8Str, 1);
    decodeBitString(BBC_2_76Str, 2);
    decodeBitString(BBC_2_51Str, 5);
    endExtension();
    decodeEndOfElement("BBC_2");       // End BBC_2

    getIElength();
    decodeOctetString(BBC_34Str, 2);

    decodeBegOfElement("BBC_5");       // Begin BBC_5
    getExtension();
    decodeBitStr(BBC_5_8Str, 1);
    decodeBitStr(BBC_5_76Str, 2);
    decodeBitStr(BBC_5_51Str, 5);
    decodeEndOfElement("BBC_5");       // End BBC_5

    // if extension is 1 then next octet not present 
    // (see. UNI3.1 Sec.5 Chap.5.4.5.7)
    if (_extensionBit == 0)
    {
        decodeBegOfElement("BBC_5A");       // Begin BBC_5A
        getExtension();
        decodeBitStr(BBC_5A_8Str, 1);
        decodeBitStr(BBC_5A_76Str, 2);
        decodeBitStr(BBC_5A_53Str, 3);
        decodeBitStr(BBC_5A_21Str, 2);
        decodeEndOfElement("BBC_5A");       // End BBC_5A
    }
    pfUlong tmp = endExtension();
    decreaseIElength(tmp*OCTETSIZE);

    decodeBegOfElement("BBC_6");       // Begin BBC_6
    getExtension();
    decodeBitStr(BBC_6_8Str, 1);
    decodeBitStr(BBC_6_76Str, 2);
    decodeBitStr(BBC_6_53Str, 3);
    decodeBitStr(BBC_6_21Str, 2);
    tmp = endExtension();
    decreaseIElength(tmp*OCTETSIZE);
    decodeEndOfElement("BBC_6");       // End BBC_6

    // if there is some extra data in ie
    storeUnknownField(_IElengthInBits);

    decodeEndOfElement("BBC");       // End BBC
    return;
}

//----------------------------------------------------------------------

//
//Function: decodeBLL_IE
//
//Description:
//      Decodes UNI Broadband low-layer information IE
//
// Type          Length   Name
// Octetstring   1        Identifier
// Bitstring     1        Extension bit
// Bitstring     2        Coding Standard
// Bitstring     5        IE Instruction Field
// Octetstring   2        Length of IE
// Hexstring     n        Broadband Low Layer Information
//
void uniPDUcoder :: decodeBLL_IE(void)
{
    debugUser("Decoding BLL IE");

    decodeBegOfElement("BLL");       // Begin BLL
    decodeOctetString(BLL_1Str, 1);
    
    decodeBegOfElement("BLL_2");       // Begin BLL_2
    getExtension();
    decodeBitString(BLL_2_8Str, 1);
    decodeBitString(BLL_2_76Str, 2);
    decodeBitString(BLL_2_51Str, 5);
    endExtension();
    decodeEndOfElement("BLL_2");       // End BLL_2

    getIElength();
    decodeOctetString(BLL_34Str, 2);

    decodeHexStr(BLL_RStr, blocksInIE(HEXSIZE));

    decodeEndOfElement("BLL");       // End BLL
    return;
}

//----------------------------------------------------------------------

//
//Function: decodeBLSH_IE
//
//Description:
//      Decodes UNI Broadband locking shift IE
//
// Type          Length   Name
// Octetstring   1        Identifier
// Bitstring     1        Extension bit
// Bitstring     2        Coding Standard
// Bitstring     5        IE Instruction Field
// Octetstring   2        Length of IE
// Bitstring     1        Extension bit
// Bitstring     4        Spare bits
// Bitstring     3        New Codeset Identification
//

void uniPDUcoder :: decodeBLSH_IE(void)
{
    debugUser("Decoding BLSH IE");

    decodeBegOfElement("BLSH");       // Begin BLSH

    decodeOctetString(BLSH_1Str, 1);
    
    decodeBegOfElement("BLSH_2");       // Begin BLSH_2
    getExtension();
    decodeBitString(BLSH_2_8Str, 1);
    decodeBitString(BLSH_2_76Str, 2);
    decodeBitString(BLSH_2_51Str, 5);
    endExtension();
    decodeEndOfElement("BLSH_2");       // End BLSH_2

    getIElength();
    decodeOctetString(BLSH_34Str, 2);

    decodeBegOfElement("BLSH_5");       // Begin BLSH_5
    getExtension();
    decodeBitStr(BLSH_5_8Str, 1);
    decodeBitStr(BLSH_5_74Str, 4);
    decodeBitStr(BLSH_5_31Str, 3);
    pfUlong tmp = endExtension();
    decreaseIElength(tmp*OCTETSIZE);
    decodeEndOfElement("BLSH_5");       // End BLSH_5

    // if there is some extra data in ie
    storeUnknownField(_IElengthInBits);

    decodeEndOfElement("BLSH");       // End BLSH

    return;
}

//----------------------------------------------------------------------

//
//Function: decodeBNSH_IE
//
//Description:
//      Decodes UNI Broadband non-locking shift IE
//
// Type          Length   Name
// Octetstring   1        Identifier
// Bitstring     1        Extension bit
// Bitstring     2        Coding Standard
// Bitstring     5        IE Instruction Field
// Octetstring   2        Length of IE
// Bitstring     1        Extension bit
// Bitstring     4        Spare bits
// Bitstring     3        Codeset Identification
//
void uniPDUcoder :: decodeBNSH_IE(void)
{
    debugUser("Decoding BNSH IE");

    decodeBegOfElement("BNSH");       // Begin BNSH
    decodeOctetString(BNSH_1Str, 1);
    
    decodeBegOfElement("BNSH_2");       // Begin BNSH_2
    getExtension();
    decodeBitString(BNSH_2_8Str, 1);
    decodeBitString(BNSH_2_76Str, 2);
    decodeBitString(BNSH_2_51Str, 5);
    endExtension();
    decodeEndOfElement("BNSH_2");       // End BNSH_2

    getIElength();
    decodeOctetString(BNSH_34Str, 2);

    decodeBegOfElement("BNSH_5");       // Begin BNSH_5
    getExtension();
    decodeBitStr(BNSH_5_8Str, 1);
    decodeBitStr(BNSH_5_74Str, 4);
    decodeBitStr(BNSH_5_31Str, 3);
    pfUlong tmp = endExtension();
    decreaseIElength(tmp*OCTETSIZE);
    decodeEndOfElement("BNSH_5");       // End BNSH_5

    // if there is some extra data in ie
    storeUnknownField(_IElengthInBits);

    decodeEndOfElement("BNSH");       // End BNSH
    return;
}

//----------------------------------------------------------------------

//
//Function: decodeBSC_IE
//
//Description:
//      Decodes UNI Broadband sending complete IE
//
// Type          Length   Name
// Octetstring   1        Identifier
// Bitstring     1        Extension bit
// Bitstring     2        Coding Standard
// Bitstring     5        IE Instruction Field
// Octetstring   2        Length of IE
// Bitstring     1        Extension bit
// Bitstring     7        Broadband Sending Complete Indication
//
void uniPDUcoder :: decodeBSC_IE(void)
{
    debugUser("Decoding BSC IE");

    decodeBegOfElement("BSC");       // Begin BSC

    decodeOctetString(BSC_1Str, 1);
    
    decodeBegOfElement("BSC_2");       // Begin BSC_2
    getExtension();
    decodeBitString(BSC_2_8Str, 1);
    decodeBitString(BSC_2_76Str, 2);
    decodeBitString(BSC_2_51Str, 5);
    endExtension();
    decodeEndOfElement("BSC_2");       // End BSC_2

    getIElength();
    decodeOctetString(BSC_34Str, 2);

    decodeBegOfElement("BSC_5");       // Begin BSC_5
    getExtension();
    decodeBitStr(BSC_5_8Str, 1);
    decodeBitStr(BSC_5_71Str, 7);
    pfUlong tmp = endExtension();
    decreaseIElength(tmp*OCTETSIZE);
    decodeEndOfElement("BSC_5");       // End BSC_5

    // if there is some extra data in ie
    storeUnknownField(_IElengthInBits);

    decodeEndOfElement("BSC");       // End BSC
    return;
}

//----------------------------------------------------------------------

//
//Function: decodeBRI_IE
//
//Description:
//      Decodes UNI Broadband repeat indicator IE
//
// Type          Length   Name
// Octetstring   1        Identifier
// Bitstring     1        Extension bit
// Bitstring     2        Coding Standard
// Bitstring     5        IE Instruction Field
// Octetstring   2        Length of IE
// Bitstring     1        Extension bit
// Bitstring     3        Spare bits
// Bitstring     4        Broadband Repeat Indicator
//
void uniPDUcoder :: decodeBRI_IE(void)
{
    debugUser("Decoding BRI IE");

    decodeBegOfElement("BRI");       // Begin BRI

    decodeOctetString(BRI_1Str, 1);

    decodeBegOfElement("BRI_2");       // Begin BRI_2
    getExtension();
    decodeBitString(BRI_2_8Str, 1);
    decodeBitString(BRI_2_76Str, 2);
    decodeBitString(BRI_2_51Str, 5);
    endExtension();
    decodeEndOfElement("BRI_2");       // End BRI_2

    getIElength();
    decodeOctetString(BRI_34Str, 2);

    decodeBegOfElement("BRI_5");       // Begin BRI_5
    getExtension();
    decodeBitStr(BRI_5_8Str, 1);
    decodeBitStr(BRI_5_75Str, 3);
    decodeBitStr(BRI_5_41Str, 4);
    pfUlong tmp = endExtension();
    decreaseIElength(tmp*OCTETSIZE);
    decodeEndOfElement("BRI_5");       // End BRI_5

    // if there is some extra data in ie
    storeUnknownField(_IElengthInBits);

    decodeEndOfElement("BRI");       // End BRI
    return;
}

//----------------------------------------------------------------------

//
//Function: decodeCGN_IE
//
//Description:
//      Decodes UNI Calling party number IE
//
// Type          Length   Name
// Octetstring   1        Identifier
// Bitstring     1        Extension bit
// Bitstring     2        Coding Standard
// Bitstring     5        IE Instruction Field
// Octetstring   2        Length of IE
// Bitstring     1        Extension bit
// Bitstring     3        Type of Number
// Bitstring     4        Addressing/Numbering Plan Indicator
// Bitstring     1        Extension bit
// Bitstring     2        Presentation Indicator
// Bitstring     3        Spare bits
// Bitstring     2        Screening Indicator
// Hexstring     n        Number Digits
//
void uniPDUcoder :: decodeCGN_IE(void)
{
    debugUser("Decoding CGN IE");

    decodeBegOfElement("CGN");       // Begin CGN

    decodeOctetString(CGN_1Str, 1);
    
    decodeBegOfElement("CGN_2");       // Begin CGN_2
    getExtension();
    decodeBitString(CGN_2_8Str, 1);
    decodeBitString(CGN_2_76Str, 2);
    decodeBitString(CGN_2_51Str, 5);
    endExtension();
    decodeEndOfElement("CGN_2");       // End CGN_2

    getIElength();
    decodeOctetString(CGN_34Str, 2);

    getExtension();
    decodeBegOfElement("CGN_5");       // Begin CGN_5
    decodeBitStr(CGN_5_8Str, 1);
    decodeBitStr(CGN_5_75Str, 3);
    decodeBitStr(CGN_5_41Str, 4);
    decodeEndOfElement("CGN_5");       // End CGN_5

    // if extension is 1 then next octet not present 
    // (see. UNI3.1 Sec.5 Chap.5.4.5.7)
    if (_extensionBit == 0)
    {
        decodeBegOfElement("CGN_5A");       // Begin CGN_5A
        getExtension();
        decodeBitStr(CGN_5A_8Str, 1);
        decodeBitStr(CGN_5A_76Str, 2);
        decodeBitStr(CGN_5A_53Str, 3);
        decodeBitStr(CGN_5A_21Str, 2);
        // endExtension?
        decodeEndOfElement("CGN_5A");       // End CGN_5A
    }
    pfUlong tmp = endExtension();
    decreaseIElength(tmp*OCTETSIZE);

    decodeHexStr(CGN_RStr, blocksInIE(HEXSIZE));

    decodeEndOfElement("CGN");       // End CGN
    return;
}

//----------------------------------------------------------------------

//
//Function: decodeCGS_IE
//
//Description:
//      Decodes UNI Calling party subaddress IE
//
// Type          Length   Name
// Octetstring   1        Identifier
// Bitstring     1        Extension bit
// Bitstring     2        Coding Standard
// Bitstring     5        IE Instruction Field
// Octetstring   2        Length of IE
// Bitstring     1        Extension bit
// Bitstring     3        Type of Subaddress
// Bitstring     1        Odd/Even Indicator
// Bitstring     3        Spare bits
// Hexstring     n        Subaddress Information
//
void uniPDUcoder :: decodeCGS_IE(void)
{
    debugUser("Decoding CGS IE");

    decodeBegOfElement("CGS");       // Begin CGS

    decodeOctetString(CGS_1Str, 1);
    
    decodeBegOfElement("CGS_2");       // Begin CGS_2
    getExtension();
    decodeBitString(CGS_2_8Str, 1);
    decodeBitString(CGS_2_76Str, 2);
    decodeBitString(CGS_2_51Str, 5);
    endExtension();
    decodeEndOfElement("CGS_2");       // End CGS_2

    getIElength();
    decodeOctetString(CGS_34Str, 2);

    decodeBegOfElement("CGS_5");       // Begin CGS_5
    getExtension();
    decodeBitStr(CGS_5_8Str, 1);
    decodeBitStr(CGS_5_75Str, 3);
    decodeBitStr(CGS_5_4Str, 1);
    decodeBitStr(CGS_5_31Str, 3);
    pfUlong tmp = endExtension();
    decreaseIElength(tmp*OCTETSIZE);
    decodeEndOfElement("CGS_5");       // End CGS_5

    decodeHexStr(CGS_RStr, blocksInIE(HEXSIZE));

    decodeEndOfElement("CGS");       // End CGS

    return;
}

//----------------------------------------------------------------------

//
//Function: decodeCDN_IE
//
//Description:
//      Decodes UNI Called party number IE
//
// Type          Length   Name
// Octetstring   1        Identifier
// Bitstring     1        Extension bit
// Bitstring     2        Coding Standard
// Bitstring     5        IE Instruction Field
// Octetstring   2        Length of IE
// Bitstring     1        Extension bit
// Bitstring     3        Type of Number
// Bitstring     4        Numbering Plan Indicator
// Hexstring     n        Number Digits
//
void uniPDUcoder :: decodeCDN_IE(void)
{
    debugUser("Decoding CDN IE");

    decodeBegOfElement("CDN");       // Begin CDN

    decodeOctetString(CDN_1Str, 1);
    
    decodeBegOfElement("CDN_2");       // Begin CDN_2
    getExtension();
    decodeBitString(CDN_2_8Str, 1);
    decodeBitString(CDN_2_76Str, 2);
    decodeBitString(CDN_2_51Str, 5);
    endExtension();
    decodeEndOfElement("CDN_2");       // End CDN_2

    getIElength();
    decodeOctetString(CDN_34Str, 2);

    decodeBegOfElement("CDN_5");       // Begin CDN_5
    getExtension();
    decodeBitStr(CDN_5_8Str, 1);
    decodeBitStr(CDN_5_75Str, 3);
    decodeBitStr(CDN_5_41Str, 4);
    pfUlong tmp = endExtension();
    decreaseIElength(tmp*OCTETSIZE);
    decodeEndOfElement("CDN_5");       // End CDN_5

    decodeHexStr(CDN_RStr, blocksInIE(HEXSIZE));

    decodeEndOfElement("CDN");       // End CDN

    return;
}

//----------------------------------------------------------------------

//
//Function: decodeCDS_IE
//
//Description:
//      Decodes UNI Called party subaddress IE
//
// Type          Length   Name
// Octetstring   1        Identifier
// Bitstring     1        Extension bit
// Bitstring     2        Coding Standard
// Bitstring     5        IE Instruction Field
// Octetstring   2        Length of IE
// Bitstring     1        Extension bit
// Bitstring     3        Type of Subaddress
// Bitstring     1        Odd/Even Indicator
// Bitstring     3        Spare bits
// Hexstring     n        Subaddress Information
//
void uniPDUcoder :: decodeCDS_IE(void)
{
    debugUser("Decoding CDS IE");

    decodeBegOfElement("CDS");       // Begin CDS

    decodeOctetString(CDS_1Str, 1);
    
    decodeBegOfElement("CDS_2");       // Begin CDS_2
    getExtension();
    decodeBitString(CDS_2_8Str, 1);
    decodeBitString(CDS_2_76Str, 2);
    decodeBitString(CDS_2_51Str, 5);
    endExtension();
    decodeEndOfElement("CDS_2");       // End CDS_2

    getIElength();
    decodeOctetString(CDS_34Str, 2);

    decodeBegOfElement("CDS_5");       // Begin CDS_5
    getExtension();
    decodeBitStr(CDS_5_8Str, 1);
    decodeBitStr(CDS_5_75Str, 3);
    decodeBitStr(CDS_5_4Str, 1);
    decodeBitStr(CDS_5_31Str, 3);
    pfUlong tmp = endExtension();
    decreaseIElength(tmp*OCTETSIZE);
    decodeEndOfElement("CDS_5");       // End CDS_5

    decodeHexStr(CDS_RStr, blocksInIE(HEXSIZE));

    decodeEndOfElement("CDS");       // End CDS

    return;
}

//----------------------------------------------------------------------

//
//Function: decodeTNS_IE
//
//Description:
//      Decodes UNI Transit network selection IE
//
// Type          Length   Name
// Octetstring   1        Identifier
// Bitstring     1        Extension bit
// Bitstring     2        Coding Standard
// Bitstring     5        IE Instruction Field
// Octetstring   2        Length of IE
// Bitstring     1        Extension bit
// Bitstring     3        Type of Network Identification
// Bitstring     4        Network Identification Plan
// IA5string     n        Network Identification
//
void uniPDUcoder :: decodeTNS_IE(void)
{
    debugUser("Decoding TNS IE");

    decodeBegOfElement("TNS");       // Begin TNS

    decodeOctetString(TNS_1Str, 1);
    
    decodeBegOfElement("TNS_2");       // Begin TNS_2
    getExtension();
    decodeBitString(TNS_2_8Str, 1);
    decodeBitString(TNS_2_76Str, 2);
    decodeBitString(TNS_2_51Str, 5);
    endExtension();
    decodeEndOfElement("TNS_2");       // End TNS_2

    getIElength();
    decodeOctetString(TNS_34Str, 2);

    decodeBegOfElement("TNS_5");       // Begin TNS_5
    getExtension();
    decodeBitStr(TNS_5_8Str, 1);
    decodeBitStr(TNS_5_75Str, 3);
    decodeBitStr(TNS_5_41Str, 4);
    pfUlong tmp = endExtension();
    decreaseIElength(tmp * OCTETSIZE);
    decodeEndOfElement("TNS_5");       // End TNS_5

    decodeIA5Str(TNS_RStr, blocksInIE(OCTETSIZE));

    decodeEndOfElement("TNS");       // End TNS

    return;
}

//----------------------------------------------------------------------

//
//Function: decodeRI_IE
//
//Description:
//      Decodes UNI Restart indicator IE
//
// Type          Length   Name
// Octetstring   1        Identifier
// Bitstring     1        Extension bit
// Bitstring     2        Coding Standard
// Bitstring     5        IE Instruction Field
// Octetstring   2        Length of IE
// Bitstring     1        Extension bit
// Bitstring     4        Spare bits
// Bitstring     3        Class
//
void uniPDUcoder :: decodeRI_IE(void)
{
    debugUser("Decoding RI IE");

    decodeBegOfElement("RI");       // Begin RI

    decodeOctetString(RI_1Str, 1);
    
    decodeBegOfElement("RI_2");       // Begin RI_2
    getExtension();
    decodeBitString(RI_2_8Str, 1);
    decodeBitString(RI_2_76Str, 2);
    decodeBitString(RI_2_51Str, 5);
    endExtension();
    decodeEndOfElement("RI_2");       // End RI_2

    getIElength();
    decodeOctetString(RI_34Str, 2);

    decodeBegOfElement("RI_5");       // Begin RI_5
    getExtension();
    decodeBitStr(RI_5_8Str, 1);
    decodeBitStr(RI_5_74Str, 4);
    decodeBitStr(RI_5_31Str, 3);
    pfUlong tmp = endExtension();
    decreaseIElength(tmp*OCTETSIZE);
    decodeEndOfElement("RI_5");       // End RI_5

    // if there is some extra data in ie
    storeUnknownField(_IElengthInBits);

    decodeEndOfElement("RI");       // End RI

    return;
}

//----------------------------------------------------------------------

//
//Function: decodeUN_IE
//
//Description:
//      Decodes unknown IE
//
// Type          Length   Name
// Octetstring   1        Identifier
// Bitstring     1        Extension bit
// Bitstring     2        Coding Standard
// Bitstring     1        Flag
// Bitstring     2        Spare
// Bitstring     2        IE Action Indicator
// Octetstring   2        Length of IE
//
void uniPDUcoder :: decodeUN_IE(void)
{
    printWarningMsg("Decoding UN IE");

    decodeBegOfElement("UN");       // Begin UN

    decodeOctetString(UN_1Str, 1);
    
    decodeBegOfElement("UN_2");       // Begin UN_2
    getExtension();
    decodeBitString(UN_2_8Str, 1);
    decodeBitString(UN_2_76Str, 2);
    decodeBitString(UN_2_5Str, 1);
    decodeBitString(UN_2_43Str, 2);
    decodeBitString(UN_2_21Str, 2);
    endExtension();
    decodeEndOfElement("RI");       // End UN_2

    getIElength();
    decodeOctetString(UN_34Str, 2);

    storeUnknownField(_IElengthInBits);

    decodeEndOfElement("UN");       // End UN

    return;
}


//----------------------------------------------------------------------

//
//Function: getExtension
//
//Description:
//      Gets extensionBit from databuffer. If databuffer is empty then default
//      value to extensionBit is 1 (last octet).
//
void uniPDUcoder :: getExtension(void)
{
    if (_dataBuffer.length() > 0)
    {
        if ((_dataBuffer.length() % OCTETSIZE) != 0)
        {
            printErrorMsg(
                "getExtension: dataBuffer length not 8-bit aligned");
        }
        _extensionBit = _dataBuffer.readBits(0, 1);
    }
    else
    {
        printErrorMsg("getExtension: databuffer empty");
        _extensionBit = 1;
    }

    return;
}
//----------------------------------------------------------------------

//
//Function: endExtension
//
//Description:
//      Skip possible extra extension fields. 1(true) means last octet.
//
pfUlong uniPDUcoder :: endExtension(void)
{
    pfUlong skippedOctets = 0;
    pfBitString tmp;
    string skippedData("");

    if ((_dataBuffer.length() % OCTETSIZE) != 0)
    {
        printErrorMsg("endExtension: dataBuffer length not 8-bit aligned");
    }

    while (_extensionBit == 0)
    {
        if (_dataBuffer.length() < OCTETSIZE)
        {
            THROW_TEMPORARY_FAILURE;
        }
        getExtension();
        tmp = pfBitString(_dataBuffer.toString(OCTETSIZE));
        skippedData = bitStringToOctetString(tmp);
        _dataBuffer.getFirstBits(OCTETSIZE); // removes octet from databuffer.
        ++skippedOctets;
        debugString("Unexpected extension - skipped", skippedData);
    }

    return skippedOctets;
}

//----------------------------------------------------------------------

//
//Function: decodeBitStr
//
//Description:
//      Decodes bitstring from databuffer and checks IElength.
//
void uniPDUcoder :: decodeBitStr(const string &name_, pfUlong length_)
{
    if (_IElengthInBits >= length_)
    {
        decodeBitString(name_, length_);
        decreaseIElength(length_);
    }
    else if (_IElengthInBits != 0)
    {
        printErrorMsg("Not enough data in IE");

        decodeBitString(name_, _IElengthInBits);
        decreaseIElength(_IElengthInBits);
    }
    else
    {
        printErrorMsg("No more data in IE");
    }

    return;
}

//----------------------------------------------------------------------

//
//Function: decodeOctetStr
//
//Description:
//      Decodes octetstring from databuffer and checks IElength.
//
void uniPDUcoder :: decodeOctetStr(const string &name_, pfUlong length_)
{
    if (_IElengthInBits >= (length_ * OCTETSIZE))
    {
        decodeOctetString(name_, length_);
        decreaseIElength(length_ * OCTETSIZE);
    }
    else if (_IElengthInBits != 0)
    {
        printErrorMsg("Not enough data in IE");

        pfBitString tmp =
	    pfBitString(_dataBuffer.toString(_IElengthInBits));
        removeData(_IElengthInBits);
        forceToBlockSize(tmp, OCTETSIZE);
        string octetValue = bitStringToOctetString(tmp);
        insertToMessage(name_, octetValue, otMessage::OctetString);
        decreaseIElength(_IElengthInBits);
    }
    else
    {
        printErrorMsg("No more data in IE");
    }

    return;
}

//----------------------------------------------------------------------

//
//Function: decodeHexStr
//
//Description:
//      Decodes hexstring from databuffer and checks IElength.
//
void uniPDUcoder :: decodeHexStr(const string &name_, pfUlong length_)
{
    if (_IElengthInBits >= length_*HEXSIZE)
    {
        decodeHexString(name_, length_);
        decreaseIElength(length_*HEXSIZE);
    }
    else if (_IElengthInBits != 0)
    {
        printErrorMsg("Not enough data in IE");

        pfBitString tmp = 
            pfBitString(_dataBuffer.toString(_IElengthInBits));
        removeData(_IElengthInBits);
        forceToBlockSize(tmp, HEXSIZE);
        string hexValue = bitStringToOctetString(tmp);
        insertToMessage(name_, hexValue, otMessage::HexString);
        decreaseIElength(_IElengthInBits);
    }
    else
    {
        printErrorMsg("No more data in IE");
    }

    return;
}

//----------------------------------------------------------------------

//
//Function: decodeIA5Str
//
//Description:
//      Decodes IA5string from databuffer and checks IElength.
//
void uniPDUcoder :: decodeIA5Str(const string &name_, pfUlong length_)
{
    if (_IElengthInBits >= (length_ * OCTETSIZE))
    {
        decodeIA5String(name_, length_);
        decreaseIElength(length_ * OCTETSIZE);
    }
    else if (_IElengthInBits != 0)
    {
        printErrorMsg("Not enough data in IE");

        pfBitString tmp(_dataBuffer.toString(_IElengthInBits));
        removeData(_IElengthInBits);
        forceToBlockSize(tmp, OCTETSIZE);
        char IA5char;
        string IA5value("");

        while (tmp.length() != 0)
        {
            tmp.getFirstBits(1);
            IA5char = (char)tmp.getFirstBits(7);
            IA5value += IA5char;
        }

        insertToMessage(name_, IA5value, otMessage::CharString);
        decreaseIElength(_IElengthInBits);
    }
    else
    {
        printErrorMsg("No more data in IE");
    }

    return;
}

//----------------------------------------------------------------------

//
//Function: getIElength
//
//Description:
//      Gets IElength from databuffer and if it is less than 16 bits sets it 
//      to 0. Also if databuffer's length is less than IE's length
//      IE's length is set to databuffer's length.
//

void uniPDUcoder :: getIElength(void)
{
    if (_dataBuffer.length() >= 16)
    {
        _IElengthInBits = _dataBuffer.readBits(0, 16) * OCTETSIZE;

        if (_IElengthInBits > (_dataBuffer.length() - 16))
        {
            printErrorMsg(
                "getIElength: dataBuffer has less data than IE length shows");
            _IElengthInBits = _dataBuffer.length() - 16;
        }
    }
    else
    {
        printErrorMsg("getIElength: not enough data in dataBuffer");
        _IElengthInBits = 0;
    }

    return;
}

//----------------------------------------------------------------------

//
//Function: decreaseIElength
//
//Description:
//      Decreases given amount of bits from IElength and checks that IElength
//      does not overflow
//

void uniPDUcoder :: decreaseIElength(pfUlong bits_)
{
    if (_IElengthInBits >= bits_)
    {
        _IElengthInBits -= bits_;
    }
    else
    {
        printErrorMsg("decreaseIElength: IE length underflow");
        _IElengthInBits = 0;
    }

    return;
}

//----------------------------------------------------------------------

//
//Function: blocksInIE
//
//Description:
//      Returns number of blocks (size of blockSize_) left in IE.
//      If there are extra bits method returns number of blocks + 1.
//      This method is called at the end of decodeXX_IE method and
//      checks if the length of the IE exceeds the spec. The excess
//      bits are added to the last value field of the IE.
//
pfUlong uniPDUcoder :: blocksInIE(const pfUlong blockSize_)
{
    pfUlong result = 0;
    pfUlong extraBits = _IElengthInBits % blockSize_;

    result = _IElengthInBits / blockSize_;

    if (extraBits != 0)
    {
        printErrorMsg("blocksInIE: IElength is not blockSize_-aligned");
        ++result;
    }

    return result;
}

//----------------------------------------------------------------------
