DT_2_IndicatePData(PRIVATE_NETWORKKEY ** /*network*/,
         PRIVATE_ASSOCIATIONKEY ** association, int nextState, void * /*params*/)
{
    unsigned char
        pduType,
        pduReserved;
    unsigned long
        pduLength,
        pdvLength,
        pdvCount;
    long
        length;
    unsigned char
       *p;

    /* determine the finite state machine's next state */
    (*association)->protocolState = nextState;

    /* read PDU body information from the incoming socket stream. In case the incoming */
    /* PDU's header information has not yet been read, also read this information. */
    OFCondition cond = readPDUBody(association, DUL_BLOCK, 0,
                       (*association)->fragmentBuffer,
                       (*association)->fragmentBufferLength,
                       &pduType, &pduReserved, &pduLength);

    /* return error if there was one */
    if (cond.bad())
        return cond;

    /* count the amount of PDVs in the current PDU */
    length = pduLength;                     //set length to the PDU's length
    pdvCount = 0;                           //set counter variable to 0
    p = (*association)->fragmentBuffer;     //set p to the buffer which contains the PDU's PDVs
    while (length >= 4) {                   //as long as length is at least 4 (= a length field can be read)
        EXTRACT_LONG_BIG(p, pdvLength);     //determine the length of the current PDV (the PDV p points to)
        p += 4 + pdvLength;                 //move p so that it points to the next PDV (move p 4 bytes over the length field plus the amount of bytes which is captured in the PDV's length field (over presentation context.Id, message information header and data fragment))
        length -= 4 + pdvLength;            //update length (i.e. determine the length of the buffer which has not been evaluated yet.)
        pdvCount++;                         //increase counter by one, since we've found another PDV

        // There must be at least a presentation context ID and a message
        // control header (see below), else the calculation pdvLength - 2 below
        // will underflow.
        if (pdvLength < 2)
        {
           char buf[256];
           sprintf(buf, "PDV with invalid length %lu encountered. This probably indicates a malformed P DATA PDU.", pdvLength);
           return makeDcmnetCondition(DULC_ILLEGALPDULENGTH, OF_error, buf);
        }
    }

    /* if after having counted the PDVs the length variable does not equal */
    /* 0, the PDV lengths did not add up correctly. Something is fishy. */
    if (length != 0)
    {
       char buf[256];
       sprintf(buf, "PDV lengths don't add up correctly: %d PDVs. This probably indicates a malformed P-DATA PDU. PDU type is %02x.", (int)pdvCount, (unsigned int) pduType);
       return makeDcmnetCondition(DULC_ILLEGALPDU, OF_error, buf);
    }

    /* let the the association indicate how many PDVs are contained in the PDU */
    (*association)->pdvCount = (int)pdvCount;

    /* if at least one PDV is contained in the PDU, the association's pdvIndex has to be set to 0 */
    if (pdvCount > 0)
        (*association)->pdvIndex = 0;
    else
    {
        /* if there is no PDV contained in the PDU, the association's pdvIndex has to be set to -1 */
        (*association)->pdvIndex = -1;

        /* bugfix by wilkens 01/10/12: return error if PDU does not contain any PDVs: */
        /* Additionally, it is not allowed to have a PDU that does not contain any PDVs. */
        /* Hence, return an error (see DICOM standard (year 2000) part 8, section 9.3.1, */
        /* figure 9-2) (or the corresponding section in a later version of the standard) */
       char buf[256];
       sprintf(buf, "PDU without any PDVs encountered. In DT_2_IndicatePData.  This probably indicates a  malformed P DATA PDU." );
       return makeDcmnetCondition(DULC_ILLEGALPDU, OF_error, buf);
    }

    /* at this point we need to set the association's currentPDV variable so that it contains the data */
    /* of the next unprocessed PDV (currentPDV shall always contain the next unprocessed PDV's data.) */

    /* set the fragment buffer (the buffer which contains all PDVs of the current PDU) to a local variable */
    p = (*association)->fragmentBuffer;

    /* The variable (*association)->pdvPointer always points to the buffer */
    /* address where the information of the PDV which is represented by the */
    /* association's currentPDV variable can be found. Set this variable. */
    (*association)->pdvPointer = p;

    /* determine the value in the PDV length field of the next (unprocessed) PDV */
    EXTRACT_LONG_BIG(p, pdvLength);

    /* set the data fragment length in the association's currentPDV.fragmentLength variable */
    /* (we start now overwriting all the entries in (*association)->currentPDV). The actual */
    /* length of the data fragment of the next (unprocessed) PDV equals the above determined */
    /* length minus 1 byte (for the presentation context ID) and minus another byte (for the */
    /* message control header). */
    (*association)->currentPDV.fragmentLength = pdvLength - 2;

    /* set the presentation context ID value in the association's currentPDV.presentationContextID */
    /* variable. This value is 1 byte wide and contained in the 5th byte of p (the first four bytes */
    /* contain the PDV length value, the fifth byte the presentation context ID value) */
    (*association)->currentPDV.presentationContextID = p[4];

    /* now determine if the next (unprocessed) PDV contains the last fragment of a data set or DIMSE */
    /* command and if the next (unprocessed) PDV is a data set PDV or command PDV. This information */
    /* is captured in the 6th byte of p: */
    unsigned char u = p[5];
    if (u & 2)
        (*association)->currentPDV.lastPDV = OFTrue;            //if bit 1 of the message control header is 1, this fragment does contain the last fragment of a data set or command
    else
        (*association)->currentPDV.lastPDV = OFFalse;           //if bit 1 of the message control header is 0, this fragment does not contain the last fragment of a data set or command

    if (u & 1)
        (*association)->currentPDV.pdvType = DUL_COMMANDPDV;    //if bit 0 of the message control header is 1, this is a command PDV
    else
        (*association)->currentPDV.pdvType = DUL_DATASETPDV;    //if bit 0 of the message control header is 0, this is a data set PDV

    /* now assign the data fragment of the next (unprocessed) PDV to the association's */
    /* currentPDV.data variable. The fragment starts 6 bytes to the right of the address */
    /* p currently points to. */
    (*association)->currentPDV.data = p + 6;

    /* return ok */
    return DUL_PDATAPDUARRIVED;
}
DT_2_IndicatePData(PRIVATE_NETWORKKEY **  ,
         PRIVATE_ASSOCIATIONKEY ** association, int nextState, void *  )
{
    unsigned char
        pduType,
        pduReserved;
    unsigned long
        pduLength,
        pdvLength,
        pdvCount;
    long
        length;
    unsigned char
       *p;

     
    (*association)->protocolState = nextState;

     
     
    OFCondition cond = readPDUBody(association, DUL_BLOCK, 0,
                       (*association)->fragmentBuffer,
                       (*association)->fragmentBufferLength,
                       &pduType, &pduReserved, &pduLength);

     
    if (cond.bad())
        return cond;

     
    length = pduLength;                      
    pdvCount = 0;                            
    p = (*association)->fragmentBuffer;      
    while (length >= 4) {                    
        EXTRACT_LONG_BIG(p, pdvLength);      
        p += 4 + pdvLength;                  
        length -= 4 + pdvLength;             
        pdvCount++;                          

         
         
         
        if (pdvLength < 2)
        {
           char buf[256];
           sprintf(buf, "PDV with invalid length %lu encountered. This probably indicates a malformed P DATA PDU.", pdvLength);
           return makeDcmnetCondition(DULC_ILLEGALPDULENGTH, OF_error, buf);
        }
    }

     
     
    if (length != 0)
    {
       char buf[256];
       sprintf(buf, "PDV lengths don't add up correctly: %d PDVs. This probably indicates a malformed P-DATA PDU. PDU type is %02x.", (int)pdvCount, (unsigned int) pduType);
       return makeDcmnetCondition(DULC_ILLEGALPDU, OF_error, buf);
    }

     
    (*association)->pdvCount = (int)pdvCount;

     
    if (pdvCount > 0)
        (*association)->pdvIndex = 0;
    else
    {
         
        (*association)->pdvIndex = -1;

         
         
         
         
       char buf[256];
       sprintf(buf, "PDU without any PDVs encountered. In DT_2_IndicatePData.  This probably indicates a  malformed P DATA PDU." );
       return makeDcmnetCondition(DULC_ILLEGALPDU, OF_error, buf);
    }

     
     

     
    p = (*association)->fragmentBuffer;

     
     
     
    (*association)->pdvPointer = p;

     
    EXTRACT_LONG_BIG(p, pdvLength);

     
     
     
     
     
    (*association)->currentPDV.fragmentLength = pdvLength - 2;

     
     
     
    (*association)->currentPDV.presentationContextID = p[4];

     
     
     
    unsigned char u = p[5];
    if (u & 2)
        (*association)->currentPDV.lastPDV = OFTrue;             
    else
        (*association)->currentPDV.lastPDV = OFFalse;            

    if (u & 1)
        (*association)->currentPDV.pdvType = DUL_COMMANDPDV;     
    else
        (*association)->currentPDV.pdvType = DUL_DATASETPDV;     

     
     
     
    (*association)->currentPDV.data = p + 6;

     
    return DUL_PDATAPDUARRIVED;
}