//--------------------------------------------------------------------//
        //                                                        M e t h o d //
        // r e a d R e s p o n s e                                            //
        //--------------------------------------------------------------------//
        //                                                                    //
        // Read response from target.                                         //
        //                                                                    //
        // There should be TWO FormFeeds in the returned data:                //
        //  - first one after return of ECHO data;                            //
        //  - second one after end of response data;                          //
        //                                                                    //
        // With some printers, a minimum of two 'reads' are necessary with    //
        // PJL Status Readback, because:                                      //
        //  - the first read reads the ECHO (identifying) data (terminated    //
        //    with a Form Feed byte).                                         //
        //  - the second read reads the actual response data (also terminated //
        //    with a FormFeed byte).                                          //
        //                                                                    //
        // With other printers, the response data is concatenated with the    //
        // echo data, so a single read may be all that is necessary.          //
        //                                                                    //
        // In each case, multiple reads may be required if the length of the  //
        // returned data exceeds the read 'chunk' size.                       //
        //                                                                    //
        // And some printers may respond with bits of data less than the      //
        // 'chunk' size, if there is a lot to return, but it is still         //
        // necessary to carry on reading until the terminating <FF> byte is   //
        // found.                                                             //
        //                                                                    //
        //--------------------------------------------------------------------//

        public static String readResponse()
        {
            const Int32 replyBufLen = 32768;

            Byte[] replyData = new Byte[replyBufLen];

            Int32 replyLen = 0;

            Boolean readFF_A      = false;       // two <FF>s expected //
            Boolean OK            = false;
            Boolean replyComplete = false;

            Int32 offset    = 0;
            Int32 endOffset = 0;
            Int32 bufRem    = replyBufLen;
            Int32 blockLen  = 0;

            while (!replyComplete)
            {
                OK = TargetCore.responseReadBlock(offset,
                                                  bufRem,
                                                  ref replyData,
                                                  ref blockLen);

                endOffset = offset + blockLen;

                if (!OK)
                {
                    replyComplete = true;
                }
                else if (!readFF_A)
                {
                    //--------------------------------------------------------//
                    //                                                        //
                    // Not yet found any <FF> bytes.                          //
                    // Search buffer to see if first, or both first and       //
                    // second <FF> (as applicable) are present.               //
                    //                                                        //
                    // This branch is expected to be entered since we include //
                    // a PJL ECHO commmand in the job header.                 //
                    //                                                        //
                    //--------------------------------------------------------//

                    for (Int32 i = offset; i < endOffset; i++)
                    {
                        if (replyData[i] == 0x0c)
                        {
                            if ((readFF_A) && (replyData[endOffset - 1] == 0x0c))
                            {
                                replyComplete = true;
                            }
                            else
                            {
                                readFF_A = true;
                            }
                        }
                    }
                }
                else
                {
                    //--------------------------------------------------------//
                    //                                                        //
                    // <FF> at end of ECHO text is either not expected, or    //
                    // has been read in a previous read action.               //
                    //                                                        //
                    //--------------------------------------------------------//

                    if (replyData[endOffset - 1] == 0x0c)
                    {
                        //----------------------------------------------------//
                        //                                                    //
                        // Terminating <FF> found (as last byte of data       //
                        // returned by current read action).                  //
                        //                                                    //
                        //----------------------------------------------------//

                        replyComplete = true;
                    }
                }

                offset += blockLen;
                bufRem -= blockLen;

                if (bufRem <= 0)
                {
                    replyComplete = true;
                }
            }

            replyLen = endOffset;

            TargetCore.responseCloseConnection();

            return(System.Text.Encoding.ASCII.GetString(replyData,
                                                        0,
                                                        replyLen));
        }
        //--------------------------------------------------------------------//
        //                                                        M e t h o d //
        // r e a d R e s p o n s e U p l o a d                                //
        //--------------------------------------------------------------------//
        //                                                                    //
        // Read standard response from PJL FileSystem query; request types:   //
        //  -   FSUPLOAD                                                      //
        //                                                                    //
        // Response from printer expected - write this direct to the target   //
        // file (it could be (much) larger than the standard reply buffer.    //
        //                                                                    //
        // The response terminates with a FormFeed byte, but the binary data  //
        // returned may also include FormFeed bytes, so have to ignore those  //
        // ones.                                                              //
        //                                                                    //
        // Also, at least one printer (LaserJet M553x) appears to return      //
        // extra bytes (sometimes hundreds or more) between the end of the    //
        // upload (of a size determined by the SIZE parameter returned at the //
        // start of the response) and the terminating <FF>.                   //
        // This is presumably a firmware bug?                                 //
        //                                                                    //
        //--------------------------------------------------------------------//

        private static String readResponseUpload(String binTgtFilename)
        {
            const Int32 replyBufLen = 32768;

            String reply = "";

            Boolean binFileOpen = false;

            binFileOpen = binTgtFileOpen(binTgtFilename);

            if (!binFileOpen)
            {
                reply = "Failed to open target binary file:\r\n\r\n" +
                        binTgtFilename;
            }
            else
            {
                Int32  binSize    = -1;
                Byte[] replyBlock = new Byte[replyBufLen];

                //   Boolean readFF_A = true;    // only one <FF> expected //
                Boolean OK             = true;
                Boolean replyComplete  = false;
                Boolean firstBlock     = true;
                Boolean supDataWritten = false;

                Int32 offset    = 0;
                Int32 endOffset = 0;
                Int32 bufRem    = replyBufLen;
                Int32 blockLen  = 0;
                Int32 binLen    = 0;
                Int32 binTot    = 0;
                Int32 binRem    = 0;
                Int32 supLen    = 0;

                while (OK && !replyComplete)
                {
                    OK = TargetCore.responseReadBlock(offset,
                                                      bufRem,
                                                      ref replyBlock,
                                                      ref blockLen);

                    endOffset = offset + blockLen;

                    if (!OK)
                    {
                        replyComplete = true;
                    }

                    /*else if (!readFF_A)
                     * {
                     *  //--------------------------------------------------------//
                     *  //                                                        //
                     *  // Not yet found any <FF> bytes.                          //
                     *  // Search buffer to see if first, or both first and       //
                     *  // second <FF> (as applicable) are present.               //
                     *  //                                                        //
                     *  // This branch will never be entered unless we include a  //
                     *  // PJL ECHO commmand in the job header; included in case  //
                     *  // we ever do this.                                       //
                     *  //                                                        //
                     *  //--------------------------------------------------------//
                     *
                     *  for (Int32 i = offset; i < endOffset; i++)
                     *  {
                     *      if (replyData[i] == 0x0c)
                     *      {
                     *          if ((readFF_A) && (replyData[endOffset - 1] == 0x0c))
                     *              replyComplete = true;
                     *          else
                     *              readFF_A = true;
                     *      }
                     *  }
                     * }*/
                    else
                    {
                        //--------------------------------------------------------//
                        //                                                        //
                        // <FF> at end of ECHO text is either not expected, or    //
                        // has been read in a previous read action.               //
                        //                                                        //
                        //--------------------------------------------------------//

                        if (replyBlock[endOffset - 1] == 0x0c)
                        {
                            //----------------------------------------------------//
                            //                                                    //
                            // Terminating <FF> found (as last byte of data       //
                            // returned by current read action).                  //
                            //                                                    //
                            //----------------------------------------------------//

                            replyComplete = true;
                        }
                    }

                    if (firstBlock)
                    {
                        //--------------------------------------------------------//
                        //                                                        //
                        // Assume that the first block of the response data will  //
                        // contain (at least) the complete PJL FSUPLOAD command   //
                        // with its parameters.                                   //
                        //                                                        //
                        //--------------------------------------------------------//

                        Int32 cmdLen;

                        firstBlock = false;

                        cmdLen = Array.IndexOf(replyBlock,
                                               PrnParseConstants.asciiLF,
                                               0, blockLen);

                        if (cmdLen != -1)
                        {
                            //----------------------------------------------------//
                            //                                                    //
                            // Terminating <LF> byte of PJL command found.        //
                            // Search for the value associated with the SIZE      //
                            // parameter.                                         //
                            //                                                    //
                            //----------------------------------------------------//

                            cmdLen += 1;    // account for <LF> byte //

                            binSize = readResponseUploadSize(replyBlock, cmdLen);

                            reply = Encoding.ASCII.GetString(replyBlock,
                                                             0,
                                                             cmdLen) +
                                    "\r\n" +
                                    binSize + " bytes will be written to the" +
                                    " target file:" + "\r\n\r\n" +
                                    binTgtFilename;

                            binLen = blockLen - cmdLen;

                            if (replyComplete)
                            {
                                // terminating <FF> found; ignore this in count
                                binLen -= 1;
                            }

                            binRem = binSize;

                            if (binRem > binLen)
                            {
                                supLen = 0;
                                binRem = binRem - binLen;
                            }
                            else if (binRem < binLen)
                            {
                                supLen = binLen - binRem;
                                binLen = binRem;
                                binRem = 0;
                            }
                            else
                            {
                                supLen = 0;
                                binRem = 0;
                            }

                            binTot = binLen;

                            binTgtFileWrite(replyBlock, cmdLen, binLen);
                        }
                        else
                        {
                            //----------------------------------------------------//
                            //                                                    //
                            // Terminating <LF> byte of PJL command NOT found.    //
                            // Send response blocks to the binary file for        //
                            // diagnostic purposes.                               //
                            //                                                    //
                            //----------------------------------------------------//

                            reply = "SIZE data not found at start of response" +
                                    "\r\n\r\n" +
                                    "All response data will be written to the" +
                                    " target file:" + "\r\n\r\n" +
                                    binTgtFilename;

                            binSize = -1;
                            binRem  = 0;

                            binTgtFileWrite(replyBlock, 0, blockLen);
                        }
                    }
                    else
                    {
                        //--------------------------------------------------------//
                        //                                                        //
                        // Not the first response block.                          //
                        //                                                        //
                        //--------------------------------------------------------//

                        if (binSize == -1)
                        {
                            // write everything to target file //
                            binLen = blockLen;
                        }
                        else
                        {
                            binLen = blockLen;

                            if (replyComplete)
                            {
                                // terminating <FF> found; ignore this in count
                                binLen -= 1;
                            }

                            if (binRem > binLen)
                            {
                                binRem = binRem - binLen;
                            }
                            else if (binRem < binLen)
                            {
                                supLen += (binLen - binRem);
                                binLen  = binRem;
                                binRem  = 0;
                            }
                            else
                            {
                                binRem = 0;
                            }
                        }

                        binTot += binLen;

                        binTgtFileWrite(replyBlock, 0, binLen);
                    }

                    if ((supLen != 0) && (!supDataWritten))
                    {
                        supDataWritten = true;

                        reply += "\r\n\r\n" +
                                 "Response from device contains extra" +
                                 " bytes after the binary data of size " +
                                 binSize + " bytes.\r\n" +
                                 "Here are the first " + supLen +
                                 " such bytes:\r\n\r\n" +
                                 ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>" +
                                 "\r\n" +
                                 Encoding.ASCII.GetString(replyBlock,
                                                          binLen,
                                                          supLen) +
                                 "\r\n" +
                                 "<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<";
                    }
                }

                //--------------------------------------------------------//
                //                                                        //
                // Response complete.                                     //
                // Close connection and output binary file.               //
                //                                                        //
                //--------------------------------------------------------//

                TargetCore.responseCloseConnection();

                binTgtFileClose();

                //--------------------------------------------------------//
                //                                                        //
                // Supplement reply data with details of any              //
                // inconsistencies.                                       //
                //                                                        //
                //--------------------------------------------------------//

                if (binTot < binSize)
                {
                    reply += "\r\n\r\n" +
                             "Response contains only " + binTot +
                             " bytes of binary data, but " + binSize +
                             " bytes were expected!";
                }

                if (supLen != 0)
                {
                    reply += "\r\n\r\n" +
                             "Response from device contains an extra " +
                             supLen + " bytes after the binary data!";
                }
            }

            return(reply);
        }