/*!
  @file           IFRConversion_ByteCharDataConverter.cpp
  @author         D039759
  @ingroup        IFR_DataConv
  @brief
  @see

\if EMIT_LICENCE

    ========== licence begin  GPL
    Copyright (c) 2001-2005 SAP AG

    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License
    as published by the Free Software Foundation; either version 2
    of the License, or (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
    ========== licence end



\endif
*/
#include "SAPDB/Interfaces/Runtime/IFR_Common.h"
#include "SAPDB/Interfaces/Runtime/IFR_Connection.h"
#include "SAPDB/Interfaces/Runtime/Conversion/IFRConversion_ByteCharDataConverter.h"
#include "SAPDB/Interfaces/Runtime/Util/IFRUtil_SQLNumeric.h"
#include "SAPDB/SAPDBCommon/MemoryManagement/SAPDBMem_Alloca.h"
#include "hsp83.h"

#include <errno.h>
#include <ctype.h>
#include <stdlib.h>

#if defined(NMP) && !defined(BIT64)
extern "C" long long strtoll (const char *, char**, int);
extern "C" unsigned long long strtoull (const char *, char**, int);
#endif

#if defined(HPUX) && !defined(BIT64)
extern "C" intmax_t __strtoll (const char *, char**, int);
extern "C" uintmax_t __strtoull (const char *, char**, int);
#  define strtoull __strtoull
#  define strtoll  __strtoll
#endif

#define DBUG_CLINK_METHOD_ENTER(x,y) DBUG_CONTEXT_METHOD_ENTER(x, y, &clink)

// //----------------------------------------------------------------------
// static IFR_size_t string_nlen(char *s, IFR_size_t max)
// {
//     for(IFR_size_t i=0; i<max; ++i) {
//         if(*(s+i) == 0) {
//             return i;
//         }
//     }
//     return max;
// }

// //----------------------------------------------------------------------
// static inline IFR_size_t compute_input_datalength(IFR_size_t datalength,
//                                                   IFR_Length *lengthindicator,
//                                                   char      *data,
//                                                   IFR_ConnectionItem& clink,
//                                                   IFR_Int4            index,
//                                                   IFR_Bool&           error)
// {
//     error=false;
//     if(lengthindicator) {
//         if(*lengthindicator==IFR_NTS) {
//             if(datalength != 0) {
//                 return string_nlen(data, datalength);
//             } else {
//                 return strlen(data);
//             }
//         } else if(*lengthindicator < 0) {
//             clink.error().setRuntimeError(IFR_ERR_INVALID_LENGTHINDICATOR_I, index);
//             error=true;
//             return 0;
//         } else if (*lengthindicator >= 0) {
//             if(datalength != 0) {
//                 return  (IFR_Length) datalength < *lengthindicator ? datalength : *lengthindicator;
//             } else {
//                 return *lengthindicator;
//             }
//         }
//     }
//     if(datalength != 0) {
//         return string_nlen(data, datalength);
//     } else {
//         return strlen(data);
//     }
// }


//----------------------------------------------------------------------
IFRConversion_ByteCharDataConverter
::IFRConversion_ByteCharDataConverter(IFR_ShortInfo &shortinfo,
                                      SAPDBMem_IRawAllocator& allocator,
                                      IFR_Bool istrimming,
                                      IFR_Bool integerconversion)
:IFRConversion_Converter(shortinfo, allocator)
{
    m_flags.trimming          = (istrimming) ? 1 : 0 ;
    m_flags.numbers           = (integerconversion) ? 1 : 0;
    m_flags.binary_as_encoded = 0;
    m_partencoding = IFR_StringEncodingAscii;
}

//----------------------------------------------------------------------
IFRConversion_ByteCharDataConverter::~IFRConversion_ByteCharDataConverter()
{
}


//----------------------------------------------------------------------
IFR_Retcode
IFRConversion_ByteCharDataConverter
::translateBinaryInput(IFRPacket_DataPart& datapart,
                       char               *data,
                       IFR_Length            datalength,
                       IFR_Length*           lengthindicator,
                       IFR_ConnectionItem & clink)
{
    DBUG_CLINK_METHOD_ENTER(IFRConversion_Converter, translateBinaryInput);
    IFR_Length offset = 0;
    DBUG_RETURN(appendBinaryInput(datapart, data, datalength, lengthindicator, clink, offset, 0));
}

//----------------------------------------------------------------------
IFR_Retcode
IFRConversion_ByteCharDataConverter
::appendBinaryInput(IFRPacket_DataPart& datapart,
                    char               *data,
                    IFR_Length            datalength,
                    IFR_Length*           lengthindicator,
                    IFR_ConnectionItem & clink,
                    IFR_Length         &offset,
                    IFRConversion_Putval *putval)
{
    DBUG_CLINK_METHOD_ENTER(IFRConversion_ByteCharDataConverter, appendBinaryInput);

    IFR_Length byteslength;
    if(IFRConversion_InputDataLength(datalength, lengthindicator, data, byteslength)) {
        clink.error().setRuntimeError(IFR_ERR_INVALID_LENGTHINDICATOR_I, (IFR_Int4)getIndex());
        DBUG_RETURN(IFR_NOT_OK);
    }

    IFR_Retcode rc;
    IFR_Length old_offset=offset;
    
    if(offset == 0) {
        offset=byteslength;
        rc = datapart.addBinaryParameter(data, byteslength, m_shortinfo);
    } else {
        rc = datapart.appendBinaryToParameter(data, byteslength, m_shortinfo, offset);
    }

    switch(rc) {
    case IFR_NOT_OK:
        clink.error().setRuntimeError(IFR_ERR_CONVERSION_NOT_SUPPORTED_I, (IFR_Int4)getIndex());
        DBUG_RETURN(rc);
    case IFR_OK:
        break;
    case IFR_DATA_TRUNC:
        offset = m_shortinfo.iolength - 1;
        if(m_flags.trimming) {
            if(offset >= old_offset + IFRConversion_StringPadLength(data, byteslength, m_shortinfo.getPaddingCharacter())) {
                rc = IFR_OK;
                break;
            }
        }
        rc = IFR_NOT_OK;
    default:
        clink.error().setRuntimeError(IFR_ERR_PARAM_CONVERSION_TRUNCATEDATA_I, (IFR_Int4)getIndex());
    }
    
    DBUG_RETURN(rc);
}




//----------------------------------------------------------------------
IFR_Retcode
IFRConversion_ByteCharDataConverter
::translateAsciiInput(IFRPacket_DataPart& datapart,
                      char               *data,
                      IFR_Length            datalength,
                      IFR_Length*           lengthindicator,
                      IFR_ConnectionItem &clink)
{
    DBUG_CLINK_METHOD_ENTER(IFRConversion_ByteCharDataConverter, translateAsciiInput);
    IFR_Length  offset = 0;
    DBUG_RETURN(appendAsciiInput(datapart, data, datalength, lengthindicator, clink, offset, 0));
}


//----------------------------------------------------------------------
IFR_Retcode
IFRConversion_ByteCharDataConverter
::appendAsciiInput(IFRPacket_DataPart& datapart,
                   char               *data,
                   IFR_Length            datalength,
                   IFR_Length*           lengthindicator,
                   IFR_ConnectionItem &clink,
                   IFR_Length&         offset,
                   IFRConversion_Putval *putval)
{
    DBUG_CLINK_METHOD_ENTER(IFRConversion_ByteCharDataConverter, appendAsciiInput);
    DBUG_PRINT(datalength);
    DBUG_PRINT(lengthindicator);
    DBUG_PRINT(offset);

    IFR_Length byteslength;
    if(IFRConversion_InputDataLength(datalength, lengthindicator, data, byteslength)) {
        clink.error().setRuntimeError(IFR_ERR_INVALID_LENGTHINDICATOR_I, (IFR_Int4)getIndex());
        DBUG_RETURN(IFR_NOT_OK);
    }

    IFR_Retcode rc;
    IFR_Length old_offset=offset;
    
    if(offset == 0) {
        offset=byteslength;
        rc = datapart.addParameter(data, byteslength, IFR_StringEncodingAscii, IFR_StringEncodingAscii, m_shortinfo);
    } else {
        rc = datapart.appendToParameter(data, byteslength, IFR_StringEncodingAscii, IFR_StringEncodingAscii, m_shortinfo, offset);
    }
    

    switch(rc) {
    case IFR_NOT_OK:
        clink.error().setRuntimeError(IFR_ERR_CONVERSION_NOT_SUPPORTED_I, (IFR_Int4)getIndex());
        DBUG_RETURN(rc);
    case IFR_OK:
        break;
    case IFR_DATA_TRUNC:
        offset = m_shortinfo.iolength - 1;
        if(m_flags.trimming) {
            if(offset >= old_offset + IFRConversion_StringPadLength(data, byteslength, m_shortinfo.getPaddingCharacter())) {
                rc = IFR_OK;
                break;
            }
        }
        rc = IFR_NOT_OK;
    default:
        clink.error().setRuntimeError(IFR_ERR_PARAM_CONVERSION_TRUNCATEDATA_I, (IFR_Int4)getIndex());
    }
    
    DBUG_RETURN(rc);
}



IFR_Retcode
IFRConversion_ByteCharDataConverter
::translateUCS2Input(IFRPacket_DataPart& datapart,
                     char               *data,
                     IFR_Bool            swapped,
                     IFR_Length            datalength,
                     IFR_Length*           lengthindicator,
                     IFR_ConnectionItem &clink)
{
    DBUG_CLINK_METHOD_ENTER(IFRConversion_ByteCharDataConverter, translateUCS2Input);
    IFR_Length offset = 0;
    DBUG_RETURN(appendUCS2Input(datapart, data, swapped, datalength, lengthindicator, clink, offset, 0));
}

//----------------------------------------------------------------------
IFR_Retcode
IFRConversion_ByteCharDataConverter
::appendUCS2Input(IFRPacket_DataPart& datapart,
                     char               *data,
                     IFR_Bool            swapped,
                     IFR_Length            datalength,
                     IFR_Length*           lengthindicator,
                     IFR_ConnectionItem &clink,
                     IFR_Length&         offset,
                     IFRConversion_Putval *putval)
{
    DBUG_CLINK_METHOD_ENTER(IFRConversion_ByteCharDataConverter, appendUCS2Input);
    
    // Target encoding is ASCII, source encoding is some UCS2
    IFR_Length byteslength;
    if(IFRConversion_InputDataLengthUCS2(datalength, lengthindicator, data, byteslength)) {
        clink.error().setRuntimeError(IFR_ERR_INVALID_LENGTHINDICATOR_I, (IFR_Int4)getIndex());
        DBUG_RETURN(IFR_NOT_OK);
    }
    if(byteslength % 2) {
        clink.error().setRuntimeError(IFR_ERR_ODD_DATALENGTH_I, (IFR_Int4)this->m_index);
        DBUG_RETURN(IFR_NOT_OK);
    }
    
    IFR_Retcode rc = IFR_OK;
    IFR_Length old_offset = offset;
    if(offset == 0) {
        offset = byteslength;
        rc = datapart.addParameter(data,
                                   byteslength,
                                   swapped?IFR_StringEncodingUCS2Swapped:IFR_StringEncodingUCS2,
                                   IFR_StringEncodingAscii,
                                   m_shortinfo);
    } else {
        rc = datapart.appendToParameter(data,
                                        byteslength,
                                        swapped?IFR_StringEncodingUCS2Swapped:IFR_StringEncodingUCS2,
                                        IFR_StringEncodingAscii,
                                        m_shortinfo,
                                        offset);
    }
    switch(rc) {
    case IFR_NOT_OK:
        clink.error().setRuntimeError(IFR_ERR_CORRUPTED_UCS2ASCIIDATA_I, (IFR_Int4)getIndex());
        break;
    case IFR_OK:
        break;
    case IFR_DATA_TRUNC: 
        offset = (m_shortinfo.iolength - 1) * 2; // iolength is bytes in ascii, needed is ucs2
        if(m_flags.trimming) {
            if(offset >= old_offset + IFRConversion_StringPadLengthUCS2(data, byteslength, 
                                                                        m_shortinfo.getPaddingCharacter(), swapped)) {
                rc = IFR_OK;
                break;
            }
        }
    default:
        rc = IFR_NOT_OK;
        clink.error().setRuntimeError(IFR_ERR_PARAM_CONVERSION_TRUNCATEDATA_I, (IFR_Int4)getIndex());
    }
    DBUG_RETURN(rc);
}


//----------------------------------------------------------------------
IFR_Retcode
IFRConversion_ByteCharDataConverter
::translateUTF8Input(IFRPacket_DataPart& datapart,
                     char               *data,
                     IFR_Length            datalength,
                     IFR_Length*           lengthindicator,
                     IFR_ConnectionItem &clink)
{
    DBUG_CLINK_METHOD_ENTER(IFRConversion_ByteCharDataConverter, translateUTF8Input);
    IFR_Length offset = 0;
    DBUG_RETURN(appendUTF8Input(datapart, data, datalength, lengthindicator,  clink, offset, 0));
}


//----------------------------------------------------------------------
IFR_Retcode
IFRConversion_ByteCharDataConverter
::appendUTF8Input(IFRPacket_DataPart& datapart,
                  char               *data,
                  IFR_Length            datalength,
                  IFR_Length*           lengthindicator,
                  IFR_ConnectionItem &clink,
                  IFR_Length&         offset,
                  IFRConversion_Putval *putval)
{
    DBUG_CLINK_METHOD_ENTER(IFRConversion_ByteCharDataConverter, appendUTF8Input);
    
    IFR_Length byteslength;
    if(IFRConversion_InputDataLength(datalength, lengthindicator, data, byteslength)) {
        clink.error().setRuntimeError(IFR_ERR_INVALID_LENGTHINDICATOR_I, (IFR_Int4)getIndex());
        DBUG_RETURN(IFR_NOT_OK);
    }
    unsigned int bytecount = 0;
    unsigned int charcount = 0;
    int terminated = 0;
    int corrupted = 0;
    int exhausted = 0;
    sp83UTF8StringInfo(data,
                       byteslength,
                       1,
                       &charcount,
                       &bytecount,
                       &terminated,
                       &corrupted,
                       &exhausted);
    if(exhausted || corrupted) {
        clink.error().setRuntimeError(IFR_ERR_CORRUPTED_UTF8DATA_I, (IFR_Int4)getIndex());
        DBUG_RETURN(IFR_NOT_OK);
    }

    char *tmp_data = (char *)alloca(charcount + 1);
    unsigned int replacecount;
    unsigned int bytecount_ascii;
    unsigned int scrBytesParsed;
    tsp83UTF8_ConversionResult r=
        sp83UTF8toASCII((const unsigned char*)data,
                        charcount,
                        &scrBytesParsed,
                        tmp_data,
                        charcount,
                        '?',
                        &replacecount,
                        &bytecount_ascii);

    if(r != sp83UTF8Convert_Success) {
        clink.error().setRuntimeError(IFR_ERR_CORRUPTED_UTF8DATA_I, (IFR_Int4)getIndex());
        DBUG_RETURN(IFR_NOT_OK);
    }
    
    // and now the insert itself ...
    IFR_Length   tmp_datalength=charcount;
    IFR_Length tmp_lengthindicator=charcount;

    IFR_Retcode rc=appendAsciiInput(datapart, tmp_data, tmp_datalength,
                                    &tmp_lengthindicator, clink, offset, putval);

    DBUG_RETURN(rc);
}


//----------------------------------------------------------------------
IFR_Retcode
IFRConversion_ByteCharDataConverter::translateInput(IFRPacket_DataPart& datapart,
                                                    IFR_Int1&           data,
                                                    IFR_Length*           lengthindicator,
                                                    IFR_ConnectionItem& clink)

{
    DBUG_CLINK_METHOD_ENTER(IFRConversion_ByteCharDataConverter, translateInput_Int1);
    if(!m_flags.numbers) {
        clink.error().setRuntimeError(IFR_ERR_CONVERSION_NOT_SUPPORTED_I, (IFR_Int4)this->m_index);
        DBUG_RETURN(IFR_NOT_OK);
    }

    char buffer[5];
    sp77sprintf(buffer, sizeof(buffer), "%d", data);
    DBUG_PRINTS(data(IFR_Int1), buffer);
    IFR_Retcode rc = moveDataToPart(datapart, buffer, strlen(buffer), clink.error());
    if(rc == IFR_DATA_TRUNC) {
      clink.error().setRuntimeError(IFR_ERR_PARAM_CONVERSION_LOOSEDIGITS_I, (IFR_Int4)this->m_index);
      DBUG_RETURN(IFR_NOT_OK);
    }
    DBUG_RETURN(IFR_OK);
}

//----------------------------------------------------------------------
IFR_Retcode
IFRConversion_ByteCharDataConverter::translateInput(IFRPacket_DataPart& datapart,
                                                    IFR_UInt1&           data,
                                                    IFR_Length*           lengthindicator,
                                                    IFR_ConnectionItem& clink)

{
    DBUG_CLINK_METHOD_ENTER(IFRConversion_ByteCharDataConverter, translateInput_UInt1);

    if(!m_flags.numbers) {
        clink.error().setRuntimeError(IFR_ERR_CONVERSION_NOT_SUPPORTED_I, (IFR_Int4)this->m_index);
        DBUG_RETURN(IFR_NOT_OK);
    }

    char buffer[4];
    sp77sprintf(buffer, sizeof(buffer), "%u", data);
    DBUG_PRINTS(data(IFR_UInt1), buffer);
    IFR_Retcode rc = moveDataToPart(datapart, buffer, strlen(buffer), clink.error());
    if(rc == IFR_DATA_TRUNC) {
        clink.error().setRuntimeError(IFR_ERR_PARAM_CONVERSION_LOOSEDIGITS_I, (IFR_Int4)this->m_index);
        DBUG_RETURN(IFR_NOT_OK);
    }

    DBUG_RETURN(IFR_OK);
}

//----------------------------------------------------------------------
IFR_Retcode
IFRConversion_ByteCharDataConverter::translateInput(IFRPacket_DataPart& datapart,
                                                    IFR_Int2&           data,
                                                    IFR_Length*           lengthindicator,
                                                    IFR_ConnectionItem& clink)

{
    DBUG_CLINK_METHOD_ENTER(IFRConversion_ByteCharDataConverter, translateInput_Int2);

    if(!m_flags.numbers) {
        clink.error().setRuntimeError(IFR_ERR_CONVERSION_NOT_SUPPORTED_I, (IFR_Int4)this->m_index);
        DBUG_RETURN(IFR_NOT_OK);
    }

    char buffer[7];
    sp77sprintf(buffer, sizeof(buffer), "%hd", data);
    DBUG_PRINTS(data(IFR_Int2), buffer);
    IFR_Retcode rc = moveDataToPart(datapart, buffer, strlen(buffer), clink.error());
    if(rc == IFR_DATA_TRUNC) {
        clink.error().setRuntimeError(IFR_ERR_PARAM_CONVERSION_LOOSEDIGITS_I, (IFR_Int4)this->m_index);
        DBUG_RETURN(IFR_NOT_OK);
    }

    DBUG_RETURN(IFR_OK);
}

//----------------------------------------------------------------------
IFR_Retcode
IFRConversion_ByteCharDataConverter::translateInput(IFRPacket_DataPart& datapart,
                                                    IFR_UInt2&           data,
                                                    IFR_Length*           lengthindicator,
                                                    IFR_ConnectionItem& clink)

{
    DBUG_CLINK_METHOD_ENTER(IFRConversion_ByteCharDataConverter, translateInput_UInt2);

    if(!m_flags.numbers) {
        clink.error().setRuntimeError(IFR_ERR_CONVERSION_NOT_SUPPORTED_I, (IFR_Int4)this->m_index);
        DBUG_RETURN(IFR_NOT_OK);
    }

    char buffer[6];
    sp77sprintf(buffer, sizeof(buffer), "%hu", data);
    DBUG_PRINTS(data(IFR_UInt2), buffer);
    IFR_Retcode rc = moveDataToPart(datapart, buffer, strlen(buffer), clink.error());
    if(rc == IFR_DATA_TRUNC) {
        clink.error().setRuntimeError(IFR_ERR_PARAM_CONVERSION_LOOSEDIGITS_I, (IFR_Int4)this->m_index);
        DBUG_RETURN(IFR_NOT_OK);
    }

    DBUG_RETURN(IFR_OK);
}

//----------------------------------------------------------------------
IFR_Retcode
IFRConversion_ByteCharDataConverter::translateInput(IFRPacket_DataPart& datapart,
                                                    IFR_Int4&           data,
                                                    IFR_Length*           lengthindicator,
                                                    IFR_ConnectionItem& clink)

{
    DBUG_CLINK_METHOD_ENTER(IFRConversion_ByteCharDataConverter, translateInput_Int4);

    if(!m_flags.numbers) {
        clink.error().setRuntimeError(IFR_ERR_CONVERSION_NOT_SUPPORTED_I, (IFR_Int4)this->m_index);
        DBUG_RETURN(IFR_NOT_OK);
    }

    char buffer[32];
    sp77sprintf(buffer, sizeof(buffer), "%d", data);
    DBUG_PRINTS(data(IFR_Int4), buffer);
    IFR_Retcode rc = moveDataToPart(datapart, buffer, strlen(buffer), clink.error());
    if(rc == IFR_DATA_TRUNC) {
        clink.error().setRuntimeError(IFR_ERR_PARAM_CONVERSION_LOOSEDIGITS_I, (IFR_Int4)this->m_index);
        DBUG_RETURN(IFR_NOT_OK);
    }

    DBUG_RETURN(IFR_OK);
}

//----------------------------------------------------------------------
IFR_Retcode
IFRConversion_ByteCharDataConverter::translateInput(IFRPacket_DataPart& datapart,
                                                    IFR_UInt4&           data,
                                                    IFR_Length*           lengthindicator,
                                                    IFR_ConnectionItem& clink)

{
    DBUG_CLINK_METHOD_ENTER(IFRConversion_ByteCharDataConverter, translateInput_UInt4);

    if(!m_flags.numbers) {
        clink.error().setRuntimeError(IFR_ERR_CONVERSION_NOT_SUPPORTED_I, (IFR_Int4)this->m_index);
        DBUG_RETURN(IFR_NOT_OK);
    }

    char buffer[32];
    sp77sprintf(buffer, sizeof(buffer), "%u", data);
    DBUG_PRINTS(data(IFR_UInt4), buffer);
    IFR_Retcode rc = moveDataToPart(datapart, buffer, strlen(buffer), clink.error());
    if(rc == IFR_DATA_TRUNC) {
        clink.error().setRuntimeError(IFR_ERR_PARAM_CONVERSION_LOOSEDIGITS_I, (IFR_Int4)this->m_index);
        DBUG_RETURN(IFR_NOT_OK);
    }

    DBUG_RETURN(IFR_OK);
}

//----------------------------------------------------------------------
IFR_Retcode
IFRConversion_ByteCharDataConverter::translateInput(IFRPacket_DataPart& datapart,
                                                    IFR_Int8&           data,
                                                    IFR_Length*           lengthindicator,
                                                    IFR_ConnectionItem& clink)

{
    DBUG_CLINK_METHOD_ENTER(IFRConversion_ByteCharDataConverter, translateInput_Int8);

    if(!m_flags.numbers) {
        clink.error().setRuntimeError(IFR_ERR_CONVERSION_NOT_SUPPORTED_I, (IFR_Int4)this->m_index);
        DBUG_RETURN(IFR_NOT_OK);
    }

    char buffer[32];
    sp77sprintf(buffer, sizeof(buffer), "%qd", data);
    DBUG_PRINTS(data(IFR_Int8), buffer);
    IFR_Retcode rc = moveDataToPart(datapart, buffer, strlen(buffer), clink.error());
    if(rc == IFR_DATA_TRUNC) {
        clink.error().setRuntimeError(IFR_ERR_PARAM_CONVERSION_LOOSEDIGITS_I, (IFR_Int4)this->m_index);
        DBUG_RETURN(IFR_NOT_OK);
    }

    DBUG_RETURN(IFR_OK);
}

//----------------------------------------------------------------------
IFR_Retcode
IFRConversion_ByteCharDataConverter::translateInput(IFRPacket_DataPart& datapart,
                                                    IFR_UInt8&           data,
                                                    IFR_Length*           lengthindicator,
                                                    IFR_ConnectionItem& clink)

{
    DBUG_CLINK_METHOD_ENTER(IFRConversion_ByteCharDataConverter, translateInput_UInt8);

    if(!m_flags.numbers) {
        clink.error().setRuntimeError(IFR_ERR_CONVERSION_NOT_SUPPORTED_I, (IFR_Int4)this->m_index);
        DBUG_RETURN(IFR_NOT_OK);
    }

    char buffer[32];
    sp77sprintf(buffer, sizeof(buffer), "%qu", data);
    DBUG_PRINTS(data(IFR_UInt8), buffer);
    IFR_Retcode rc = moveDataToPart(datapart, buffer, strlen(buffer), clink.error());
    if(rc == IFR_DATA_TRUNC) {
        clink.error().setRuntimeError(IFR_ERR_PARAM_CONVERSION_LOOSEDIGITS_I, (IFR_Int4)this->m_index);
        DBUG_RETURN(IFR_NOT_OK);
    }

    DBUG_RETURN(IFR_OK);
}

//----------------------------------------------------------------------
IFR_Retcode
IFRConversion_ByteCharDataConverter::moveDataToPart(IFRPacket_DataPart& datapart,
                                                    char *buffer,
                                                    IFR_size_t bufferlength,
                                                    IFR_ErrorHndl &error )
{
    // prevent an overflow in this case
    IFR_Int2 used_bufferlength=
        (bufferlength > MAX_IFR_INT2) ? MAX_IFR_INT2 : (IFR_Int2)bufferlength;
    IFR_Retcode rc = datapart.addParameter(buffer, used_bufferlength, IFR_StringEncodingAscii, m_partencoding, m_shortinfo);
    if (rc == IFR_NOT_OK)
        error.setRuntimeError(IFR_ERR_CORRUPTED_UCS2ASCIIDATA_I, (IFR_Int4)getIndex());
    return rc;
}

//----------------------------------------------------------------------
IFR_Retcode
IFRConversion_ByteCharDataConverter::translateInput(IFRPacket_DataPart& datapart,
                                                    double&             data,
                                                    IFR_Length*           lengthindicator,
                                                    IFR_ConnectionItem& clink)
{
    DBUG_CLINK_METHOD_ENTER(IFRConversion_ByteCharDataConverter, translateInput_double);
    // @todo:
    // implement double to char
    DBUG_RETURN(IFR_NOT_OK);
}

//----------------------------------------------------------------------
IFR_Retcode
IFRConversion_ByteCharDataConverter::translateInput(IFRPacket_DataPart& datapart,
                                                    float&             data,
                                                    IFR_Length*          lengthindicator,
                                                    IFR_ConnectionItem& clink)
{
    DBUG_CLINK_METHOD_ENTER(IFRConversion_ByteCharDataConverter, translateInput_float);
    // @todo:
    // implement float to char
    DBUG_RETURN(IFR_NOT_OK);
}


//----------------------------------------------------------------------
static int day_in_month[] = { -1, 31, -1, 31, 30, 31, 30, 31, 31, 30,
                              31, 30, 31 };

//----------------------------------------------------------------------
static int
check_date_valid(SQL_DATE_STRUCT& sqldate)
{
    // years start counting with 1
    if(sqldate.year < 1 ||
       sqldate.month < 1 || sqldate.month > 12
       || sqldate.day < 1) {
        return 1;
    }
    if(sqldate.month != 2) {
        return sqldate.day > day_in_month[sqldate.month];
    } else {
        if((sqldate.year%400==0) || (sqldate.year%4==0 && sqldate.year%100!=0)) {
            return sqldate.day > 29;
        } else {
            return sqldate.day > 28;
        }
    }
}

//----------------------------------------------------------------------
IFR_Retcode
IFRConversion_ByteCharDataConverter::translateInput(IFRPacket_DataPart& part,
                                                    SQL_DATE_STRUCT&    data,
                                                    IFR_Length*           lengthindicator,
                                                    IFR_ConnectionItem& clink)

{
    DBUG_CLINK_METHOD_ENTER(IFRConversion_ByteCharDataConverter, translateInput_DATE);


    if(check_date_valid(data)) {
        clink.error().setRuntimeError(IFR_ERR_ILLEGAL_DATE_VALUE_I, (IFR_Int4)this->m_index);
        DBUG_RETURN(IFR_NOT_OK);
    }


    int datetimeformat=clink.getConnection()->getDateTimeFormat();
    char buffer[11];
    int dlen;            // chars in buffer for date


    switch(datetimeformat) {
     case IFR_DateTimeFormat::Normal_C:
         sp77sprintf(buffer, sizeof(buffer), "%.4hd%.2hd%.2hd", data.year, data.month, data.day);
         dlen=8;
         break;
     case IFR_DateTimeFormat::Iso_C:
     case IFR_DateTimeFormat::Jis_C:
     case IFR_DateTimeFormat::WasAnsiNowIsSameAsIso_C:
         sp77sprintf(buffer, sizeof(buffer), "%.4hd-%.2hd-%.2hd", data.year, data.month, data.day);
         dlen=10;
         break;
     default:
         clink.error().setRuntimeError(IFR_ERR_DATETIMEFORMAT_UNSUPPORTED_I, (IFR_Int4)this->m_index);
         DBUG_RETURN(IFR_NOT_OK);
     }

    if(moveDataToPart(part, buffer, dlen, clink.error()) == IFR_DATA_TRUNC) {
        clink.error().setRuntimeError(IFR_ERR_PARAM_CONVERSION_TRUNCATEDATA_I, (IFR_Int4)this->m_index);
        DBUG_RETURN(IFR_NOT_OK);
    }

    DBUG_RETURN(IFR_OK);
}


//----------------------------------------------------------------------
int check_time_valid(SQL_TIME_STRUCT& sqltime)
{
    return sqltime.hour > 23 ||
        sqltime.minute > 59  ||
        sqltime.second > 59;
}


//----------------------------------------------------------------------
IFR_Retcode
IFRConversion_ByteCharDataConverter::translateInput(IFRPacket_DataPart& part,
                                                    SQL_TIME_STRUCT&    data,
                                                    IFR_Length*           lengthindicator,
                                                    IFR_ConnectionItem& clink)
{
    DBUG_CLINK_METHOD_ENTER(IFRConversion_ByteCharDataConverter, translateInput_TIME);

    if(check_time_valid(data)) {
        clink.error().setRuntimeError(IFR_ERR_ILLEGAL_TIME_VALUE_I, (IFR_Int4)this->m_index);
        DBUG_RETURN(IFR_NOT_OK);
    }

    char buffer[9];
    int tlen;

    switch(clink.getConnection()->getDateTimeFormat()) {
    case IFR_DateTimeFormat::Normal_C:
        sp77sprintf(buffer, sizeof(buffer), "%.2hd%.2hd%.2hd", data.hour, data.minute, data.second);
        tlen=6;
        break;
    case IFR_DateTimeFormat::Iso_C:
    case IFR_DateTimeFormat::Jis_C:
    case IFR_DateTimeFormat::WasAnsiNowIsSameAsIso_C:
        sp77sprintf(buffer, sizeof(buffer), "%.2hd:%.2hd:%.2hd", data.hour, data.minute, data.second);
        tlen=8;
        break;
    default:
        clink.error().setRuntimeError(IFR_ERR_DATETIMEFORMAT_UNSUPPORTED_I, (IFR_Int4)this->m_index);
        DBUG_RETURN(IFR_NOT_OK);
    }

    if(moveDataToPart(part, buffer, tlen, clink.error()) == IFR_DATA_TRUNC) {
        clink.error().setRuntimeError(IFR_ERR_PARAM_CONVERSION_TRUNCATEDATA_I, (IFR_Int4)this->m_index);
        DBUG_RETURN(IFR_NOT_OK);
    }
    DBUG_RETURN(IFR_OK);
}

//----------------------------------------------------------------------
static int
check_timestamp_valid(SQL_TIMESTAMP_STRUCT& ts)
{
    // years start counting with 1
    if(ts.year < 1 ||
       ts.month < 1 || ts.month > 12
       || ts.day < 1) {
        return 1;
    }
    if(ts.month != 2 && (ts.day > day_in_month[ts.month])) {
        return 1;
    }
    if(ts.month==2) {
        if((ts.year%400==0) || (ts.year%4==0 && ts.year%100!=0))   {
            if(ts.day > 29) {
                return 1;
            }
        } else {
            if(ts.day > 28) {
                return 1;
            }
        }
    }

    // now for time ...
    if(ts.month!=12 && ts.day!=31) {
        if(ts.hour > 23 ||
           ts.minute > 59 ||
           ts.second > 59 ||
           ts.fraction > 999999999ul) {
            return 1;
        }
    } else {
        if(ts.hour > 23 ||
           ts.minute > 59 ||
           ts.fraction > 999999999ul) {
            return 1;
        }
        if(ts.hour<23 || ts.minute<59) {
            if(ts.second > 59) {
                return 1;
            }
        } else {
            // leap seconds
            if(ts.second > 61) {
                return 1;
            }
        }
    }
    return 0;
}


//----------------------------------------------------------------------
IFR_Retcode
IFRConversion_ByteCharDataConverter::translateInput(IFRPacket_DataPart&   part,
                                                    SQL_TIMESTAMP_STRUCT& data,
                                                    IFR_Length*             lengthindicator,
                                                    IFR_ConnectionItem&   clink)
{
    DBUG_CLINK_METHOD_ENTER(IFRConversion_ByteCharDataConverter, translateInput_TIMESTAMP);

    if(check_timestamp_valid(data)) {
        clink.error().setRuntimeError(IFR_ERR_ILLEGAL_TIMESTAMP_VALUE_I, (IFR_Int4)this->m_index);
        DBUG_RETURN(IFR_NOT_OK);
    }


    IFR_UInt4 millis=data.fraction/1000;
    char buffer[27];
    int tslen;
    switch(clink.getConnection()->getDateTimeFormat()) {
    case IFR_DateTimeFormat::Normal_C:
        sp77sprintf(buffer, sizeof(buffer), "%.4hd%.2hd%.2hd%.2hd%.2hd%.2hd%.6u", data.year, data.month, data.day,
                data.hour, data.minute, data.second, millis);
        tslen=20;
        break;
    case IFR_DateTimeFormat::Usa_C:
    case IFR_DateTimeFormat::Eur_C:
    case IFR_DateTimeFormat::TsEur_C:
    case IFR_DateTimeFormat::Iso_C:
    case IFR_DateTimeFormat::Jis_C:
    case IFR_DateTimeFormat::WasAnsiNowIsSameAsIso_C:
        sp77sprintf(buffer, sizeof(buffer), "%.4hd-%.2hd-%.2hd %.2hd:%.2hd:%.2hd.%.6u", data.year, data.month, data.day,
                data.hour, data.minute, data.second, millis);
        tslen=26;
        break;
    default:
        clink.error().setRuntimeError(IFR_ERR_DATETIMEFORMAT_UNSUPPORTED_I, (IFR_Int4)this->m_index);
        DBUG_RETURN(IFR_NOT_OK);
    }

    if(moveDataToPart(part, buffer, tslen, clink.error()) == IFR_DATA_TRUNC) {
        clink.error().setRuntimeError(IFR_ERR_PARAM_CONVERSION_TRUNCATEDATA_I, (IFR_Int4)this->m_index);
        DBUG_RETURN(IFR_NOT_OK);
    }

    DBUG_RETURN(IFR_OK);
}

//----------------------------------------------------------------------
IFR_Retcode
IFRConversion_ByteCharDataConverter::translateInput(IFRPacket_DataPart&   part,
                                                    SQL_NUMERIC_STRUCT&   data,
                                                    IFR_Length*           lengthindicator,
                                                    IFR_ConnectionItem&   clink)
{
    DBUG_CLINK_METHOD_ENTER(IFRConversion_ByteCharDataConverter, translateInput_NUMERIC);

    if(!m_flags.numbers) {
        clink.error().setRuntimeError(IFR_ERR_CONVERSION_NOT_SUPPORTED_I, (IFR_Int4)this->m_index);
        DBUG_RETURN(IFR_NOT_OK);
    }
    char buffer[132];
    IFR_size_t bufferlength=132;

    IFR_Retcode rc = IFRUtil_SQLNumeric::numericToAsciiString(data,
                                                              buffer,
                                                              bufferlength);
    if(rc != IFR_OK) {
        clink.error().setRuntimeError(IFR_ERR_PARAM_CONVERSION_TRUNCATEDATA_I, (IFR_Int4)this->m_index);
        DBUG_RETURN(rc);
    }

    DBUG_PRINT_BUFFER(buffer, bufferlength, bufferlength, IFR_StringEncodingAscii);

    char * dotpos = (char *) memchr((void *)buffer, '.', bufferlength);
    if(dotpos == 0) {
        if(m_shortinfo.length < bufferlength) {
            clink.error().setRuntimeError(IFR_ERR_PARAM_CONVERSION_TRUNCATEDATA_I, (IFR_Int4)this->m_index);
            DBUG_RETURN(IFR_NOT_OK);
        }
    } else {
        if(m_shortinfo.length < (dotpos - buffer + 1)) {
            clink.error().setRuntimeError(IFR_ERR_PARAM_CONVERSION_TRUNCATEDATA_I, (IFR_Int4)this->m_index);
            DBUG_RETURN(IFR_NOT_OK);
        }
    }

    rc = moveDataToPart(part, buffer, bufferlength, clink.error());
    DBUG_RETURN(rc);
}

//----------------------------------------------------------------------
IFR_Retcode
IFRConversion_ByteCharDataConverter::translateInput(IFRPacket_DataPart&   part,
                                                    GUID&                 data,
                                                    IFR_Length*             lengthindicator,
                                                    IFR_ConnectionItem&   clink)
{
    DBUG_CLINK_METHOD_ENTER(IFRConversion_ByteCharDataConverter, translateInput_GUID);

    if(m_shortinfo.length < sizeof(GUID)) {
        clink.error().setRuntimeError(IFR_ERR_PARAM_CONVERSION_TRUNCATEDATA_I, (IFR_Int4)this->m_index);
        DBUG_RETURN(IFR_NOT_OK);
    }
    IFR_Length tmp_lengthindicator=sizeof(GUID);
    DBUG_RETURN(translateBinaryInput(part, (char*)&data, sizeof(GUID), &tmp_lengthindicator, clink));
}

//----------------------------------------------------------------------
IFR_Retcode
IFRConversion_ByteCharDataConverter::translateAsciiOutput(IFRPacket_DataPart& datapart,
                                                          char *data,
                                                          IFR_Length datalength,
                                                          IFR_Length *lengthindicator,
                                                          IFR_Bool    terminate,
                                                          IFR_ConnectionItem& clink)
{
    DBUG_CLINK_METHOD_ENTER(IFRConversion_ByteCharDataConverter, translateAsciiOutput);
    IFR_Length  offset     = 1;
    IFR_Length  dataoffset = 0;
    DBUG_RETURN(appendAsciiOutput(datapart, data, datalength, lengthindicator, terminate, clink, dataoffset, offset, 0));
}

//----------------------------------------------------------------------
IFR_Retcode
IFRConversion_ByteCharDataConverter::appendAsciiOutput(IFRPacket_DataPart&   datapart,
                                                       char                 *data,
                                                       IFR_Length            datalength,
                                                       IFR_Length*           lengthindicator,
                                                       IFR_Bool              terminate,
                                                       IFR_ConnectionItem   &clink,
                                                       IFR_Length&           dataoffset,
                                                       IFR_Length&           offset,
                                                       IFRConversion_Getval *getval)
{
    DBUG_CLINK_METHOD_ENTER(IFRConversion_ByteCharDataConverter, appendAsciiOutput);
    
    if(dataoffset != 0) {
        clink.error().setRuntimeError(IFR_ERR_NOT_IMPLEMENTED("output of character data at offset in output buffer"));
        DBUG_RETURN(IFR_NOT_OK);
    }

    char       *read_data   = datapart.getOutputData(m_shortinfo.pos.bufpos);
    IFR_Length  byteslength = m_shortinfo.iolength - 1;

    if(m_flags.trimming) {
        byteslength = IFRConversion_StringPadLength(read_data, byteslength, m_shortinfo.getPaddingCharacter());
    }

    IFR_Length z_offset = offset - 1;
    
    // no data found if not at begin and offset >= length
    if(z_offset && z_offset >= byteslength) {
        DBUG_RETURN(IFR_NO_DATA_FOUND);
    }

    read_data += z_offset;
    byteslength -= z_offset;
    
    IFR_Length copylength = byteslength > datalength ? datalength : byteslength;
    
    memcpy(data, read_data, copylength); 
    
    if(terminate && datalength) {
        if(copylength == datalength) {
            --copylength;
            data[copylength] = 0;
        } else {
            data[byteslength] = 0;
        }
    }
    
    offset += copylength;

    if(lengthindicator) {
        *lengthindicator = byteslength;
    }
    
    if(copylength < byteslength) {
        DBUG_RETURN(IFR_DATA_TRUNC);
    } else {
        if(terminate && !datalength) {
            DBUG_RETURN(IFR_DATA_TRUNC);
        }
        DBUG_RETURN(IFR_OK);
    }    
}

//----------------------------------------------------------------------
IFR_Retcode
IFRConversion_ByteCharDataConverter::translateBinaryOutput(IFRPacket_DataPart& datapart,
                                                           char *data,
                                                           IFR_Length datalength,
                                                           IFR_Length*lengthindicator,
                                                           IFR_ConnectionItem& clink)
{
    DBUG_CLINK_METHOD_ENTER(IFRConversion_ByteCharDataConverter, translateBinaryOutput);
    IFR_Length  offset    = 1;
    IFR_Length  dataoffset= 0;
    DBUG_RETURN(appendBinaryOutput(datapart, data, datalength, lengthindicator, clink, dataoffset, offset, 0));
}

//----------------------------------------------------------------------
IFR_Retcode
IFRConversion_ByteCharDataConverter::appendBinaryOutput(IFRPacket_DataPart&   datapart,
                                                        char                 *data,
                                                        IFR_Length            datalength,
                                                        IFR_Length*           lengthindicator,
                                                        IFR_ConnectionItem   &clink,
                                                        IFR_Length&           dataoffset,
                                                        IFR_Length&           offset,
                                                        IFRConversion_Getval *getval)
{
    DBUG_CLINK_METHOD_ENTER(IFRConversion_ByteCharDataConverter, appendBinaryOutput);

    if(dataoffset != 0) {
        clink.error().setRuntimeError(IFR_ERR_NOT_IMPLEMENTED("output of character data at offset in output buffer"));
        DBUG_RETURN(IFR_NOT_OK);
    }

    char       *read_data   = datapart.getOutputData(m_shortinfo.pos.bufpos);
    IFR_Length  byteslength = m_shortinfo.iolength - 1;

    if(m_flags.trimming) {
        byteslength = IFRConversion_StringPadLength(read_data, byteslength, m_shortinfo.getPaddingCharacter());
    }

    IFR_Length z_offset = offset - 1;
    
    // no data found if not at begin and offset >= length
    if(z_offset && z_offset >= byteslength) {
        DBUG_RETURN(IFR_NO_DATA_FOUND);
    }

    read_data += z_offset;
    byteslength -= z_offset;
    
    IFR_Length copylength = byteslength > datalength ? datalength : byteslength;
    
    memcpy(data, read_data, copylength);
    
    offset += copylength;

    if(lengthindicator) {
        *lengthindicator = byteslength;
    }
    
    if(copylength < byteslength) {
        DBUG_RETURN(IFR_DATA_TRUNC);
    } else {
        DBUG_RETURN(IFR_OK);
    }    
}

//----------------------------------------------------------------------
IFR_Retcode
IFRConversion_ByteCharDataConverter::translateUCS2Output(IFRPacket_DataPart& datapart,
                                                         char *data,
                                                         IFR_Bool swapped,
                                                         IFR_Length datalength,
                                                         IFR_Length*lengthindicator,
                                                         IFR_Bool   terminate,
                                                         IFR_ConnectionItem& clink)
{
    DBUG_CLINK_METHOD_ENTER(IFRConversion_ByteCharDataConverter, translateUCS2Output);
    IFR_Length  offset     = 1;
    IFR_Length  dataoffset = 0;
    DBUG_RETURN(appendUCS2Output(datapart, data, swapped, datalength, lengthindicator, terminate, clink, dataoffset, offset, 0));
}

//----------------------------------------------------------------------
IFR_Retcode
IFRConversion_ByteCharDataConverter::appendUCS2Output(IFRPacket_DataPart&   datapart,
                                                      char                 *data,
                                                      IFR_Bool              swapped,
                                                      IFR_Length            datalength,
                                                      IFR_Length*           lengthindicator,
                                                      IFR_Bool              terminate,
                                                      IFR_ConnectionItem   &clink,
                                                      IFR_Length&           dataoffset,
                                                      IFR_Length&           offset,
                                                      IFRConversion_Getval *getval)
{
    DBUG_CLINK_METHOD_ENTER(IFRConversion_ByteCharDataConverter, appendUCS2Output);
    
    if(dataoffset != 0) {
        clink.error().setRuntimeError(IFR_ERR_NOT_IMPLEMENTED("output of character data at offset in output buffer"));
        DBUG_RETURN(IFR_NOT_OK);
    }


    char *read_data = datapart.getOutputData(m_shortinfo.pos.bufpos);
    IFR_Length byteslength = m_shortinfo.iolength - 1;
    
    if(m_flags.trimming) {
        byteslength = IFRConversion_StringPadLength(read_data, byteslength, m_shortinfo.getPaddingCharacter());
    }
    
    IFR_Length z_offset = offset - 1;

    // no data found if not at begin and offset >= length
    if(z_offset && z_offset >= byteslength) {
        DBUG_RETURN(IFR_NO_DATA_FOUND);
    }
    
    read_data += z_offset;
    byteslength -= z_offset;

    IFR_Bool datalength_too_small = false;

    if(terminate) {
        if(datalength > 1) {
            datalength -= 2;
        } else {
            memset(data, 0, datalength);
            datalength = 0;
            datalength_too_small = true;
        }
    }
    IFR_UInt4 destbyteswritten;
    IFR_UInt4 srcbytesparsed;
    IFR_Retcode rc;
    tsp78ConversionResult conv_rc = sp78convertString(IFR_ENCODING(swapped?IFR_StringEncodingUCS2Swapped:IFR_StringEncodingUCS2),
                                                      data,
                                                      datalength,
                                                      &destbyteswritten,
                                                      false,
                                                      IFR_ENCODING(IFR_StringEncodingAscii),
                                                      read_data,
                                                      byteslength,
                                                      &srcbytesparsed);
    

    switch(conv_rc) {
    case sp78_Ok: {
        if(lengthindicator) {
            *lengthindicator = destbyteswritten;
        }
        if(terminate && !datalength_too_small) {
            data[destbyteswritten] = 0;
            data[destbyteswritten+1] = 0;
        }
        offset += srcbytesparsed;
        rc = IFR_OK;
        break;
    }
    case (sp78_TargetExhausted): {
        if(lengthindicator) {
            *lengthindicator = byteslength * 2;
        }
        if(terminate && !datalength_too_small) {
            data[destbyteswritten] = 0;
            data[destbyteswritten+1] = 0;
        }
        offset += srcbytesparsed;
        rc = IFR_DATA_TRUNC;
        break;
    }
    case (sp78_SourceExhausted):
    case (sp78_SourceCorrupted):
    default: {
        clink.error().setRuntimeError(IFR_ERR_CORRUPTED_UCS2ASCIIDATA_I, (IFR_Int4)this->m_index);
        rc = IFR_NOT_OK;
        break;
    }
    }
    
    DBUG_RETURN(rc);
}

//----------------------------------------------------------------------
IFR_Retcode
IFRConversion_ByteCharDataConverter::translateUTF8Output(IFRPacket_DataPart& datapart,
                                                         char *data,
                                                         IFR_Length datalength,
                                                         IFR_Length *lengthindicator,
                                                         IFR_Bool    terminate,
                                                         IFR_ConnectionItem& clink)
{
    DBUG_CLINK_METHOD_ENTER(IFRConversion_ByteCharDataConverter, translateUTF8Output);
    IFR_Length  offset     = 1;
    IFR_Length  dataoffset = 0;
    DBUG_RETURN(appendUTF8Output(datapart, data, datalength, lengthindicator, terminate, clink, dataoffset, offset, 0));
}

//----------------------------------------------------------------------
IFR_Retcode
IFRConversion_ByteCharDataConverter::appendUTF8Output(IFRPacket_DataPart&   datapart,
                                                      char                 *data,
                                                      IFR_Length            datalength,
                                                      IFR_Length*           lengthindicator,
                                                      IFR_Bool              terminate,
                                                      IFR_ConnectionItem   &clink,
                                                      IFR_Length&           dataoffset,
                                                      IFR_Length&           offset,
                                                      IFRConversion_Getval *getval)
{
    DBUG_CLINK_METHOD_ENTER(IFRConversion_ByteCharDataConverter, appendUTF8Output);
    if(dataoffset != 0) {
        clink.error().setRuntimeError(IFR_ERR_NOT_IMPLEMENTED("output of character data at offset in output buffer"));
        DBUG_RETURN(IFR_NOT_OK);
    }

    char *read_data = datapart.getOutputData(m_shortinfo.pos.bufpos);
    IFR_Length byteslength = m_shortinfo.iolength - 1;
    
    if(m_flags.trimming) {
        byteslength = IFRConversion_StringPadLength(read_data, byteslength, m_shortinfo.getPaddingCharacter());
    }

    IFR_Length z_offset = offset - 1;

    // no data found if not at begin and offset >= length
    if(z_offset && z_offset >= byteslength) {
        DBUG_RETURN(IFR_NO_DATA_FOUND);
    }
    
    read_data += z_offset;
    byteslength -= z_offset;

    IFR_Bool datalength_too_small = false;
    
    if(terminate) {
        if(datalength) {
            --datalength;
        } else {
            datalength_too_small = true;
        }
    }
    IFR_UInt4 destbyteswritten;
    IFR_UInt4 srcbytesparsed;
    IFR_Retcode rc;
    tsp78ConversionResult conv_rc = sp78convertString(IFR_ENCODING(IFR_StringEncodingUTF8),
                                                      data,
                                                      datalength,
                                                      &destbyteswritten,
                                                      false,
                                                      IFR_ENCODING(IFR_StringEncodingAscii),
                                                      read_data,
                                                      byteslength,
                                                      &srcbytesparsed);
    switch(conv_rc) {
    case sp78_Ok: {
        if(lengthindicator) {
            *lengthindicator = destbyteswritten;
        }
        if(terminate && !datalength_too_small) {
            data[destbyteswritten] = 0;
        }
        offset += srcbytesparsed;
        rc = IFR_OK;
        break;
    }
    case (sp78_TargetExhausted): {
        if(lengthindicator) {
            *lengthindicator = IFRConversion_StringAsciiLengthAsUTF8((unsigned char *)read_data,
                                                                     byteslength);
        }
        if(terminate && !datalength_too_small) {
            data[destbyteswritten] = 0;
        }
        offset += srcbytesparsed;
        rc = IFR_DATA_TRUNC;
        break;
    }
    case (sp78_SourceExhausted):
    case (sp78_SourceCorrupted):
    default: {
        clink.error().setRuntimeError(IFR_ERR_CORRUPTED_UTF8DATA_I, (IFR_Int4)this->m_index);
        rc = IFR_NOT_OK;
        break;
    }
    }
    
    DBUG_RETURN(rc);
}

//----------------------------------------------------------------------
template <class Integer>
IFR_Retcode
translate_integer_output(char *p,
                         Integer& result,
                         IFR_ConnectionItem& clink,
                         IFR_Int4 min_value,
                         IFR_Int4 max_value,
                         IFR_Length *lengthindicator,
                         IFR_Int4 paramindex)
{
    DBUG_CONTEXT_METHOD_ENTER(static, translate_integer_output, &clink);
    while(*p && isspace(*p)) {
         ++p;
     }
     if(*p == 0) {
         result = 0;
         if(lengthindicator)
             *lengthindicator = sizeof(Integer);
         DBUG_PRINT(lengthindicator);
         DBUG_RETURN(IFR_OK);
     }

     char *trail=0;
     long l=strtol(p, &trail, 10);
     DBUG_PRINT(l);

     // now we have the different things:
     // - there may be garbage
     // - there may be an overflow

     if( l < min_value || l > max_value) {
         clink.error().setRuntimeError(IFR_ERR_NUMERIC_OVERFLOW_I, paramindex);
         return IFR_NOT_OK;
     }
     result = (Integer) l;
     if(p == trail) {
         clink.error().setRuntimeError(IFR_ERR_INVALID_NUMERIC_VALUE_I, paramindex);
         return IFR_NOT_OK;
     }

     // trailing spaces are not treated as harmful
     while(*trail != '\0') {
         if(!isspace(*trail)) {
             return IFR_DATA_TRUNC;
         }
         ++trail;
     }

     if(lengthindicator)
         *lengthindicator = sizeof(Integer);

     DBUG_PRINT(lengthindicator);
     DBUG_RETURN(IFR_OK);
}

//----------------------------------------------------------------------
void
IFRConversion_ByteCharDataConverter::moveDataToBuffer(IFRPacket_DataPart& datapart,
                                                      char *buffer)
{
    IFR_UInt4 destbyteswritten;
    IFR_UInt4 srcbytesparsed;
    tsp78ConversionResult rc =
        sp78convertString(IFR_ENCODING(IFR_StringEncodingAscii),
                          buffer,
                          m_shortinfo.length+1,
                          &destbyteswritten,
                          true,
                          IFR_ENCODING(m_partencoding),
                          datapart.getOutputData(m_shortinfo.pos.bufpos),
                          m_shortinfo.iolength-1,
                          &srcbytesparsed);
}

//----------------------------------------------------------------------
IFR_Retcode
IFRConversion_ByteCharDataConverter::translateOutput(IFRPacket_DataPart& datapart,
                                                     IFR_Int1&             data,
                                                     IFR_Length*             lengthindicator,
                                                     IFR_ConnectionItem&   clink)
{
    DBUG_CLINK_METHOD_ENTER(IFRConversion_ByteCharDataConverter, translateOutput_Int1);

    if(!m_flags.numbers) {
        clink.error().setRuntimeError(IFR_ERR_CONVERSION_NOT_SUPPORTED_I, (IFR_Int4)this->m_index);
        DBUG_RETURN(IFR_NOT_OK);
    }

    char *buffer = (char *) alloca(m_shortinfo.length + 1);
    moveDataToBuffer(datapart, buffer);
    IFR_Retcode rc=translate_integer_output(buffer, data, clink, MIN_IFR_INT1, MAX_IFR_INT1, lengthindicator, m_index);
    DBUG_RETURN(rc);
}

//----------------------------------------------------------------------
IFR_Retcode
IFRConversion_ByteCharDataConverter::translateOutput(IFRPacket_DataPart& datapart,
                                                     IFR_Int2&             data,
                                                     IFR_Length*             lengthindicator,
                                                     IFR_ConnectionItem&   clink)
{
    DBUG_CLINK_METHOD_ENTER(IFRConversion_ByteCharDataConverter, translateOutput_Int2);

    if(!m_flags.numbers) {
        clink.error().setRuntimeError(IFR_ERR_CONVERSION_NOT_SUPPORTED_I, (IFR_Int4)this->m_index);
        DBUG_RETURN(IFR_NOT_OK);
    }
    char *buffer = (char *) alloca(m_shortinfo.length + 1);
    moveDataToBuffer(datapart, buffer);
    IFR_Retcode rc=translate_integer_output(buffer, data, clink,
                                            MIN_IFR_INT2, MAX_IFR_INT2, lengthindicator, m_index);
    DBUG_RETURN(rc);

}

//----------------------------------------------------------------------
IFR_Retcode
IFRConversion_ByteCharDataConverter::translateOutput(IFRPacket_DataPart& datapart,
                                                     IFR_UInt1&             data,
                                                     IFR_Length*             lengthindicator,
                                                     IFR_ConnectionItem&   clink)
{
    DBUG_CLINK_METHOD_ENTER(IFRConversion_ByteCharDataConverter, translateOutput_UInt1);

    if(!m_flags.numbers) {
        clink.error().setRuntimeError(IFR_ERR_CONVERSION_NOT_SUPPORTED_I, (IFR_Int4)this->m_index);
        DBUG_RETURN(IFR_NOT_OK);
    }
    char *buffer = (char *) alloca(m_shortinfo.length + 1);
    moveDataToBuffer(datapart, buffer);
    IFR_Retcode rc=translate_integer_output(buffer, data, clink, MIN_IFR_UINT1, MAX_IFR_UINT1, lengthindicator, m_index);
    DBUG_RETURN(rc);
}

//----------------------------------------------------------------------
IFR_Retcode
IFRConversion_ByteCharDataConverter::translateOutput(IFRPacket_DataPart& datapart,
                                                     IFR_UInt2&             data,
                                                     IFR_Length*             lengthindicator,
                                                     IFR_ConnectionItem&   clink)
{
    DBUG_CLINK_METHOD_ENTER(IFRConversion_ByteCharDataConverter, translateOutput_UInt2);

    if(!m_flags.numbers) {
        clink.error().setRuntimeError(IFR_ERR_CONVERSION_NOT_SUPPORTED_I, (IFR_Int4)this->m_index);
        DBUG_RETURN(IFR_NOT_OK);
    }

    char *buffer = (char *) alloca(m_shortinfo.length + 1);
    moveDataToBuffer(datapart, buffer);
    IFR_Retcode rc=translate_integer_output(buffer, data, clink,
                                            MIN_IFR_UINT2, MAX_IFR_UINT2, lengthindicator, m_index);
    DBUG_RETURN(rc);
}


//----------------------------------------------------------------------
IFR_Retcode
IFRConversion_ByteCharDataConverter::translateOutput(IFRPacket_DataPart& datapart,
                                                     IFR_UInt4& data,
                                                     IFR_Length*  lengthindicator,
                                                     IFR_ConnectionItem& clink)
{
    DBUG_CLINK_METHOD_ENTER(IFRConversion_ByteCharDataConverter, translateOutput_UInt4);

    char *buffer = (char *) alloca(m_shortinfo.length + 1);
    moveDataToBuffer(datapart, buffer);

    char *p=buffer;

    while(*p && isspace(*p)) {
        ++p;
    }
    if(*p == 0) {
        data = 0;
        if(lengthindicator)
            *lengthindicator=sizeof(IFR_UInt4);
        DBUG_PRINT(lengthindicator);
        DBUG_RETURN(IFR_OK);
    }

    if(*p == '-') {
        clink.error().setRuntimeError(IFR_ERR_NUMERIC_OVERFLOW_I, (IFR_Int4)this->m_index);
        DBUG_RETURN(IFR_NOT_OK);
    }

    char *trail=0;
    errno = 0;
    unsigned long l=strtoul(p, &trail, 10);
    DBUG_PRINT(l);

    if(errno) {
        clink.error().setRuntimeError(IFR_ERR_NUMERIC_OVERFLOW_I, (IFR_Int4)this->m_index);
        DBUG_RETURN(IFR_NOT_OK);
    }
    // on 64 bit long is 64 bit, therefore no overflow will
    // occur
#if defined(BIT64) && !defined(WIN32)
    if(l > MAX_IFR_UINT4) {
        clink.error().setRuntimeError(IFR_ERR_NUMERIC_OVERFLOW_I, (IFR_Int4)this->m_index);
        DBUG_RETURN(IFR_NOT_OK);
    }
#endif
    data = (IFR_UInt4) l;

    if(p == trail) {
        clink.error().setRuntimeError(IFR_ERR_INVALID_NUMERIC_VALUE_I, (IFR_Int4)this->m_index);
        DBUG_RETURN(IFR_NOT_OK);
    }

    // trailing spaces are not treated as harmful
    while(*trail != '\0') {
         if(!isspace(*trail)) {
             if(lengthindicator)
                 *lengthindicator=sizeof(IFR_UInt4);
             DBUG_PRINT(lengthindicator);
             DBUG_RETURN(IFR_OK);
         }
         ++trail;
     }
    if(lengthindicator)
        *lengthindicator=sizeof(IFR_UInt4);
    DBUG_PRINT(lengthindicator);
    DBUG_RETURN(IFR_OK);
}

//----------------------------------------------------------------------
IFR_Retcode
IFRConversion_ByteCharDataConverter::translateOutput(IFRPacket_DataPart& datapart,
                                                     IFR_Int4& data,
                                                     IFR_Length*  lengthindicator,
                                                     IFR_ConnectionItem& clink)
{
    DBUG_CLINK_METHOD_ENTER(IFRConversion_ByteCharDataConverter, translateOutput_Int4);

    char *buffer = (char *) alloca(m_shortinfo.length + 1);
    moveDataToBuffer(datapart, buffer);

    char *p=buffer;

    while(*p && isspace(*p)) {
        ++p;
    }
    if(*p == 0) {
        data = 0;
        if(lengthindicator)
            *lengthindicator=sizeof(IFR_Int4);
        DBUG_PRINT(lengthindicator);
        DBUG_RETURN(IFR_OK);
    }

    char *trail=0;
    errno = 0;
    long l=strtol(p, &trail, 10);
    DBUG_PRINT(l);

    if(errno) {
        clink.error().setRuntimeError(IFR_ERR_NUMERIC_OVERFLOW_I, (IFR_Int4)this->m_index);
        DBUG_RETURN(IFR_NOT_OK);
    }
    // on 64 bit long is 64 bit, therefore no overflow will
    // occur
#if defined(BIT64) && !defined(WIN32)
    if(l > MAX_IFR_INT4 || l < MIN_IFR_INT4) {
        clink.error().setRuntimeError(IFR_ERR_NUMERIC_OVERFLOW_I, (IFR_Int4)this->m_index);
        DBUG_RETURN(IFR_NOT_OK);
    }
#endif
    data = (IFR_Int4) l;

    if(p == trail) {
        clink.error().setRuntimeError(IFR_ERR_INVALID_NUMERIC_VALUE_I, (IFR_Int4)this->m_index);
        DBUG_RETURN(IFR_NOT_OK);
    }

    // trailing spaces are not treated as harmful
    while(*trail != '\0') {
         if(!isspace(*trail)) {
             if(lengthindicator)
                 *lengthindicator=sizeof(IFR_Int4);
             DBUG_PRINT(lengthindicator);
             DBUG_RETURN(IFR_OK);
         }
         ++trail;
     }
    if(lengthindicator)
        *lengthindicator=sizeof(IFR_Int4);
    DBUG_PRINT(lengthindicator);
    DBUG_RETURN(IFR_OK);
}


//----------------------------------------------------------------------
IFR_Retcode
IFRConversion_ByteCharDataConverter::translateOutput(IFRPacket_DataPart& datapart,
                                                          IFR_UInt8& data,
                                                          IFR_Length* lengthindicator,
                                                          IFR_ConnectionItem& clink)
{
    DBUG_CLINK_METHOD_ENTER(IFRConversion_ByteCharDataConverter, translateOutput_UInt8);

    char *buffer = (char *) alloca(m_shortinfo.length + 1);
    moveDataToBuffer(datapart, buffer);

    char *p=buffer;

     while(*p && isspace(*p)) {
         ++p;
     }
     if(*p == 0) {
         data = 0;
         if(lengthindicator)
             *lengthindicator=sizeof(IFR_UInt8);
         DBUG_PRINT(lengthindicator);
         DBUG_RETURN(IFR_OK);
     }


     if(*p == '-') {
         clink.error().setRuntimeError(IFR_ERR_NUMERIC_OVERFLOW_I, (IFR_Int4)this->m_index);
         DBUG_RETURN(IFR_NOT_OK);
     }

     // Nasty. On 64 bit platforms, (unsigned) long is 64 bit,
     // thus strtoul will work seamless.
     // On WIN32/64 we have to use the infamous I64 modifier.

     char *trail=0;
     errno = 0;

#if defined(BIT64) && !defined (WIN32)
     unsigned long l=strtoul(p, &trail, 10);
     DBUG_PRINT(l);

     if(errno) {
         clink.error().setRuntimeError(IFR_ERR_NUMERIC_OVERFLOW_I, (IFR_Int4)this->m_index);
         DBUG_RETURN(IFR_NOT_OK);
     }

     if(p == trail) {
         clink.error().setRuntimeError(IFR_ERR_INVALID_NUMERIC_VALUE_I, (IFR_Int4)this->m_index);
         DBUG_RETURN(IFR_NOT_OK);
     }

     data = l;

     // trailing spaces are not treated as harmful
     while(*trail != '\0') {
         if(!isspace(*trail)) {
             if(lengthindicator)
                 *lengthindicator=sizeof(IFR_UInt8);
             DBUG_PRINT(lengthindicator);
             DBUG_RETURN(IFR_OK);
         }
         ++trail;
     }
#else
#  ifdef WIN32
     IFR_UInt8 l;
     char    c;
     int num_read = sscanf(p, "%I64u%c", &l, &c);
     DBUG_PRINT(l);
     if(num_read == 0) {
         clink.error().setRuntimeError(IFR_ERR_NUMERIC_OVERFLOW_I, (IFR_Int4)this->m_index);
         DBUG_RETURN(IFR_NOT_OK);
     }

     data = l;

     if(num_read==2) {
         if(!isspace(c)) {
             clink.error().setRuntimeError(IFR_ERR_INVALID_NUMERIC_VALUE_I, (IFR_Int4)this->m_index);
             DBUG_RETURN(IFR_DATA_TRUNC);
         }
         int state=1;
         while(*p) {
             if(state==1 && isdigit(*p)) {
                 ++p;
             } else if(state==1 && isspace(*p)) {
                 state=2;
                 ++p;
             } else if(state=2 && !isspace(*p)) {
                 clink.error().setRuntimeError(IFR_ERR_INVALID_NUMERIC_VALUE_I, (IFR_Int4)this->m_index);
                 DBUG_RETURN(IFR_DATA_TRUNC);
             } else {
                 ++p;
             }
         }
     }
#  else
     unsigned long long l=strtoull(p, &trail, 10);
     DBUG_PRINT(l);

     if(errno) {
         clink.error().setRuntimeError(IFR_ERR_NUMERIC_OVERFLOW_I, (IFR_Int4)this->m_index);
         DBUG_RETURN(IFR_NOT_OK);
     }

     if(p == trail) {
         clink.error().setRuntimeError(IFR_ERR_INVALID_NUMERIC_VALUE_I, (IFR_Int4)this->m_index);
         DBUG_RETURN(IFR_NOT_OK);
     }

     data = l;

     // trailing spaces are not treated as harmful
     while(*trail != '\0') {
         if(!isspace(*trail)) {
             if(lengthindicator)
                 *lengthindicator=sizeof(IFR_UInt8);
             DBUG_PRINT(lengthindicator);
             DBUG_RETURN(IFR_OK);
         }
         ++trail;
     }
#  endif
#endif
     if(lengthindicator)
         *lengthindicator = sizeof(IFR_UInt8);
     DBUG_PRINT(lengthindicator);
     DBUG_RETURN(IFR_OK);
}

//----------------------------------------------------------------------
IFR_Retcode
IFRConversion_ByteCharDataConverter::translateOutput(IFRPacket_DataPart& datapart,
                                                          IFR_Int8& data,
                                                          IFR_Length* lengthindicator,
                                                          IFR_ConnectionItem& clink)
{
    DBUG_CLINK_METHOD_ENTER(IFRConversion_ByteCharDataConverter, translateOutput_Int8);

    char *buffer = (char *) alloca(m_shortinfo.length + 1);
    moveDataToBuffer(datapart, buffer);

    char *p=buffer;

     while(*p && isspace(*p)) {
         ++p;
     }
     if(*p == 0) {
         data = 0;
         if(lengthindicator)
             *lengthindicator=sizeof(IFR_Int8);
         DBUG_PRINT(lengthindicator);
         DBUG_RETURN(IFR_OK);
     }

     // Nasty. On 64 bit platforms, (unsigned) long is 64 bit,
     // thus strtoul will work seamless.
     // On WIN32/64 we have to use the infamous I64 modifier.

     char *trail=0;
     errno = 0;

#if defined(BIT64) && !defined (WIN32)
     unsigned long l=strtoul(p, &trail, 10);
     DBUG_PRINT(l);

     if(errno) {
         clink.error().setRuntimeError(IFR_ERR_NUMERIC_OVERFLOW_I, (IFR_Int4)this->m_index);
         DBUG_RETURN(IFR_NOT_OK);
     }

     if(p == trail) {
         clink.error().setRuntimeError(IFR_ERR_INVALID_NUMERIC_VALUE_I, (IFR_Int4)this->m_index);
         DBUG_RETURN(IFR_NOT_OK);
     }

     data = l;

     // trailing spaces are not treated as harmful
     while(*trail != '\0') {
         if(!isspace(*trail)) {
             if(lengthindicator)
                 *lengthindicator=sizeof(IFR_Int8);
             DBUG_PRINT(lengthindicator);
             DBUG_RETURN(IFR_OK);
         }
         ++trail;
     }
#else
#  ifdef WIN32
     IFR_Int8 l;
     char    c;
     int num_read = sscanf(p, "%I64d%c", &l, &c);
     DBUG_PRINT(l);
     if(num_read == 0) {
         clink.error().setRuntimeError(IFR_ERR_NUMERIC_OVERFLOW_I, (IFR_Int4)this->m_index);
         DBUG_RETURN(IFR_NOT_OK);
     }

     data = l;

     if(num_read==2) {
         if(!isspace(c)) {
             clink.error().setRuntimeError(IFR_ERR_INVALID_NUMERIC_VALUE_I, (IFR_Int4)this->m_index);
             DBUG_RETURN(IFR_DATA_TRUNC);
         }
         int state=-1;
         while(*p) {
             if(state==-1 && *p == '-') {
                 ++p;
                 state = 1;
             } else if((state==1 || state==-1) && isdigit(*p)) {
                 state = 1;
                 ++p;
             } else if(state==1 && isspace(*p)) {
                 state=2;
                 ++p;
             } else if(state=2 && !isspace(*p)) {
                 clink.error().setRuntimeError(IFR_ERR_INVALID_NUMERIC_VALUE_I, (IFR_Int4)this->m_index);
                 DBUG_RETURN(IFR_DATA_TRUNC);
             } else {
                 ++p;
             }
         }
     }
#  else
     long long l=strtoll(p, &trail, 10);
     DBUG_PRINT(l);

     if(errno) {
         clink.error().setRuntimeError(IFR_ERR_NUMERIC_OVERFLOW_I, (IFR_Int4)this->m_index);
         DBUG_RETURN(IFR_NOT_OK);
     }

     if(p == trail) {
         clink.error().setRuntimeError(IFR_ERR_INVALID_NUMERIC_VALUE_I, (IFR_Int4)this->m_index);
         DBUG_RETURN(IFR_NOT_OK);
     }

     data = l;

     // trailing spaces are not treated as harmful
     while(*trail != '\0') {
         if(!isspace(*trail)) {
             if(lengthindicator)
                 *lengthindicator=sizeof(IFR_Int8);
             DBUG_PRINT(lengthindicator);
             DBUG_RETURN(IFR_OK);
         }
         ++trail;
     }
 #  endif
 #endif
     if(lengthindicator)
         *lengthindicator = sizeof(IFR_UInt8);
     DBUG_PRINT(lengthindicator);
     DBUG_RETURN(IFR_OK);
}

//----------------------------------------------------------------------
IFR_Retcode
IFRConversion_ByteCharDataConverter
::translateOutput(IFRPacket_DataPart& datapart,
                  double&               data,
                  IFR_Length*           lengthindicator,
                  IFR_ConnectionItem &clink)
{
    DBUG_CLINK_METHOD_ENTER(IFRConversion_ByteCharDataConverter, translateOutput_double);
    
    char *buffer = (char *) alloca(m_shortinfo.length + 1);
    moveDataToBuffer(datapart, buffer);
    
    char *ep = 0;
    errno = 0;
    data = strtod(buffer, &ep);
    if(errno == ERANGE && data != 0.0) {
        // overflow
        clink.error().setRuntimeError(IFR_ERR_NUMERIC_OVERFLOW_I, (IFR_Int4)this->m_index);
        DBUG_RETURN(IFR_NOT_OK);
    }
    if(ep) {
        while(*ep) {
            if(!isspace(*ep)) {
                // trash in data
                clink.error().setRuntimeError(IFR_ERR_INVALID_NUMERIC_VALUE_I, (IFR_Int4)this->m_index);
                DBUG_RETURN(IFR_NOT_OK);
            }
            ++ep;
        }
    }
    if(lengthindicator) {
        *lengthindicator = sizeof(double);
    }
    DBUG_RETURN(IFR_OK);
}

//----------------------------------------------------------------------
IFR_Retcode
IFRConversion_ByteCharDataConverter
::translateOutput(IFRPacket_DataPart& datapart,
                  float&               data,
                  IFR_Length*           lengthindicator,
                  IFR_ConnectionItem &clink)
{
    DBUG_CLINK_METHOD_ENTER(IFRConversion_ByteCharDataConverter, translateOutput_float);
    
    double dval = 0;
    IFR_Retcode rc = translateOutput(datapart, dval, 0, clink);
    if(rc == IFR_OK) {
        if(dval > 3.4028234663852886E38 || dval < -3.4028234663852886E38f) {
            clink.error().setRuntimeError(IFR_ERR_NUMERIC_OVERFLOW_I, (IFR_Int4)this->m_index);
            DBUG_RETURN(IFR_NOT_OK);
        } else {
            data = (float) dval;
            if(lengthindicator) {
                *lengthindicator = sizeof(float);
            }
        }
    }
    DBUG_RETURN(rc);
}



//----------------------------------------------------------------------
IFR_Retcode
IFRConversion_ByteCharDataConverter::translateOutput(IFRPacket_DataPart& part,
                                                     SQL_DATE_STRUCT& data,
                                                     IFR_Length* lengthindicator,
                                                     IFR_ConnectionItem& clink)
{
    DBUG_CLINK_METHOD_ENTER(IFRConversion_ByteCharDataConverter, translateOutput_DATE);


     const char *sscanf_str;
     int   dlen;
     switch(clink.getConnection()->getDateTimeFormat()) {
     case IFR_DateTimeFormat::Normal_C:
         sscanf_str= (char *) "%4hd%2hd%2hd";
         dlen=8;
         break;
     case IFR_DateTimeFormat::Iso_C:
     case IFR_DateTimeFormat::Jis_C:
     case IFR_DateTimeFormat::WasAnsiNowIsSameAsIso_C:
         sscanf_str= (char *) "%4hd-%2hd-%2hd";
         dlen=10;
         break;
     default:
         clink.error().setRuntimeError(IFR_ERR_DATETIMEFORMAT_UNSUPPORTED_I, (IFR_Int4)this->m_index);
         DBUG_RETURN(IFR_NOT_OK);
     }
     char *temp_buffer=(char *) alloca(m_shortinfo.length + 1);
     moveDataToBuffer(part, temp_buffer);
     char *buffer=temp_buffer;
     IFR_Int c=0;
     while(c < m_shortinfo.length-dlen &&
           isspace(*buffer)) {
         ++c;
         ++buffer;
     }

     SQL_DATE_STRUCT dest;
     int scanned=sscanf(buffer, sscanf_str, &dest.year, &dest.month, &dest.day);

     if(scanned!=3) {
         clink.error().setRuntimeError(IFR_ERR_ILLEGAL_DATE_VALUE_I, (IFR_Int4)this->m_index);
         DBUG_RETURN(IFR_NOT_OK);
     }

     if(check_date_valid(dest)) {
         clink.error().setRuntimeError(IFR_ERR_ILLEGAL_DATE_VALUE_I, (IFR_Int4)this->m_index);
         DBUG_RETURN(IFR_NOT_OK);
     }

     memcpy(&data, &dest, sizeof(SQL_DATE_STRUCT));
     if(lengthindicator)
         *lengthindicator=sizeof(SQL_DATE_STRUCT);
     DBUG_RETURN(IFR_OK);
}

//----------------------------------------------------------------------
IFR_Retcode
IFRConversion_ByteCharDataConverter::translateOutput(IFRPacket_DataPart& part,
                                                     SQL_TIME_STRUCT& data,
                                                     IFR_Length*        lengthindicator,
                                                     IFR_ConnectionItem& clink)
{
    DBUG_CLINK_METHOD_ENTER(IFRConversion_ByteCharDataConverter, translateOutput_TIME);

    const char *sscanf_str;
    int   tlen;
    switch(clink.getConnection()->getDateTimeFormat()) {
    case IFR_DateTimeFormat::Normal_C:
        sscanf_str= (char *) "%4hd%2hd%2hd";
        tlen=6;
        break;
    case IFR_DateTimeFormat::Iso_C:
    case IFR_DateTimeFormat::Jis_C:
    case IFR_DateTimeFormat::WasAnsiNowIsSameAsIso_C:
        sscanf_str= (char *) "%4hd:%2hd:%2hd";
        tlen=8;
        break;
    default:
        clink.error().setRuntimeError(IFR_ERR_DATETIMEFORMAT_UNSUPPORTED_I, (IFR_Int4)this->m_index);
        DBUG_RETURN(IFR_NOT_OK);
    }

    if(m_shortinfo.length < tlen) {
        clink.error().setRuntimeError(IFR_ERR_ILLEGAL_TIME_VALUE_I, (IFR_Int4)this->m_index);
        DBUG_RETURN(IFR_NOT_OK);
    }
    char *temp_buffer=(char*) alloca(m_shortinfo.length + 1);
    moveDataToBuffer(part, temp_buffer);
    char *buffer=temp_buffer;
    IFR_Int c=0;
    while(c < m_shortinfo.length-tlen &&
          isspace(*buffer)) {
        ++c; ++buffer;
    }

    SQL_TIME_STRUCT dest;
    int scanned=sscanf(buffer, sscanf_str, &dest.hour, &dest.minute, &dest.second);
    if(scanned!=3) {
        clink.error().setRuntimeError(IFR_ERR_ILLEGAL_TIME_VALUE_I, (IFR_Int4)this->m_index);
        DBUG_RETURN(IFR_NOT_OK);
    }
    if(check_time_valid(dest)) {
        clink.error().setRuntimeError(IFR_ERR_ILLEGAL_TIME_VALUE_I, (IFR_Int4)this->m_index);
        DBUG_RETURN(IFR_NOT_OK);
    }

    memcpy(&data, &dest, sizeof(SQL_TIME_STRUCT));

    if(lengthindicator)
        *lengthindicator=sizeof(SQL_TIME_STRUCT);
    DBUG_RETURN(IFR_OK);
}

//----------------------------------------------------------------------
IFR_Retcode
IFRConversion_ByteCharDataConverter::translateOutput(IFRPacket_DataPart& part,
                                                     SQL_TIMESTAMP_STRUCT& data,
                                                     IFR_Length* lengthindicator,
                                                     IFR_ConnectionItem& clink)
{
    DBUG_CLINK_METHOD_ENTER(IFRConversion_ByteCharDataConverter, translateOutput_TIMESTAMP);

    // due to the possible absence of the milliseconds a little bit
    // more complicated.
    SQL_TIMESTAMP_STRUCT dest;
    char *temp_buffer=(char *)alloca(m_shortinfo.length + 1);
    switch(clink.getConnection()->getDateTimeFormat()) {
    case IFR_DateTimeFormat::Normal_C: {
        if(m_shortinfo.length < 14) {
            clink.error().setRuntimeError(IFR_ERR_ILLEGAL_TIMESTAMP_VALUE_I, (IFR_Int4)this->m_index);
            DBUG_RETURN(IFR_NOT_OK);
        }

        moveDataToBuffer(part, temp_buffer);
        char *buffer=temp_buffer;
        IFR_Int c=0;

        while(c<m_shortinfo.length-14 && isspace(*buffer)) {
            ++c;
            ++buffer;
        }

        if(c >= m_shortinfo.length-14) {
            clink.error().setRuntimeError(IFR_ERR_ILLEGAL_TIMESTAMP_VALUE_I, (IFR_Int4)this->m_index);
            DBUG_RETURN(IFR_OK);
        }

        dest.fraction=0;
        for(int i=0; i<14; ++i) {
            if(!isdigit(buffer[i])) {
                clink.error().setRuntimeError(IFR_ERR_ILLEGAL_DATE_VALUE_I, (IFR_Int4)this->m_index);
                DBUG_RETURN(IFR_NOT_OK);
            }
        }
        dest.year =
            (buffer[0] - '0') * 1000 +
            (buffer[1] - '0') * 100 +
            (buffer[2] - '0') * 10 +
            (buffer[3] - '0');
        dest.month =
            (buffer[4] - '0') * 10 +
            (buffer[5] - '0');
        dest.day =
            (buffer[6] - '0') * 10 +
            (buffer[7] - '0');

        dest.hour =
            (buffer[8] - '0') * 10 +
            (buffer[9] - '0');
        dest.minute =
            (buffer[10] - '0') * 10 +
            (buffer[11] - '0');
        dest.second =
            (buffer[12] - '0') * 10 +
            (buffer[13] - '0');


        // compute the fraction
        // be sloppy and simply break if it does not match
        IFR_UInt nanos=0;
        do {
            c += 14;
            if(c >= m_shortinfo.length) {
                break;
            }
            buffer+=19;
            if(*buffer != '.') {
                break;
            }
            ++c;
            ++buffer;
            IFR_UInt mul=100000000;
            while(c < m_shortinfo.length &&
                  isdigit(*buffer) &&
                  mul!=0) {
                nanos += ((*buffer)-'0') * mul;
                mul /= 10;
                ++c;
                ++buffer;
            }
        } while(0);
        dest.fraction=nanos;
        break;
    }
    case IFR_DateTimeFormat::Usa_C:
    case IFR_DateTimeFormat::Eur_C:
    case IFR_DateTimeFormat::TsEur_C:
    case IFR_DateTimeFormat::Iso_C:
    case IFR_DateTimeFormat::Jis_C:
    case IFR_DateTimeFormat::WasAnsiNowIsSameAsIso_C: {
        if(m_shortinfo.length < 19) {
            clink.error().setRuntimeError(IFR_ERR_ILLEGAL_TIMESTAMP_VALUE_I, (IFR_Int4)this->m_index);
            DBUG_RETURN(IFR_NOT_OK);
        }

        moveDataToBuffer(part, temp_buffer);
        char *buffer=temp_buffer;
        IFR_Int c=0;

        while(c<m_shortinfo.length-19 && isspace(*buffer)) {
            ++c;
            ++buffer;
        }

        if(c >= m_shortinfo.length-19) {
            clink.error().setRuntimeError(IFR_ERR_ILLEGAL_TIMESTAMP_VALUE_I, (IFR_Int4)this->m_index);
            DBUG_RETURN(IFR_OK);
        }

        dest.fraction=0;
        // this is nasty, but the fastest way to check the
        // syntax rawly.
        if(!isdigit(buffer[0]) ||
           !isdigit(buffer[1]) ||
           !isdigit(buffer[2]) ||
           !isdigit(buffer[3]) ||
           (buffer[4] != '-')  ||
           !isdigit(buffer[5]) ||
           !isdigit(buffer[6]) ||
           (buffer[7] != '-')  ||
           !isdigit(buffer[8]) ||
           !isdigit(buffer[9]) ||
           !isspace(buffer[10]) ||
           !isdigit(buffer[11]) ||
           !isdigit(buffer[12]) ||
           (buffer[13] != ':') ||
           !isdigit(buffer[14]) ||
           !isdigit(buffer[15]) ||
           (buffer[16] != ':') ||
           !isdigit(buffer[17]) ||
           !isdigit(buffer[18])) {
            clink.error().setRuntimeError(IFR_ERR_ILLEGAL_DATE_VALUE_I, (IFR_Int4)this->m_index);
            DBUG_RETURN(IFR_NOT_OK);
        }

        dest.year =
            (buffer[0] - '0') * 1000 +
            (buffer[1] - '0') * 100 +
            (buffer[2] - '0') * 10 +
            (buffer[3] - '0');
        dest.month =
            (buffer[5] - '0') * 10 +
            (buffer[6] - '0');
        dest.day =
            (buffer[8] - '0') * 10 +
            (buffer[9] - '0');

        dest.hour =
            (buffer[11] - '0') * 10 +
            (buffer[12] - '0');
        dest.minute =
            (buffer[14] - '0') * 10 +
            (buffer[15] - '0');
        dest.second =
            (buffer[17] - '0') * 10 +
            (buffer[18] - '0');

        // compute the fraction
        // be sloppy and simply break if it does not match
        IFR_UInt nanos=0;
        do {
            c += 19;
            if(c >= m_shortinfo.length) {
                break;
            }
            buffer+=19;
            if(*buffer != '.') {
                break;
            }
            ++c;
            ++buffer;
            IFR_UInt mul=100000000;
            while(c < m_shortinfo.length &&
                  isdigit(*buffer) &&
                  mul!=0) {
                nanos += ((*buffer)-'0') * mul;
                mul /= 10;
                ++c;
                ++buffer;
            }
        } while(0);
        dest.fraction=nanos;
        break;
    }
    default:
        clink.error().setRuntimeError(IFR_ERR_DATETIMEFORMAT_UNSUPPORTED_I, (IFR_Int4)this->m_index);
        DBUG_RETURN(IFR_NOT_OK);
    }
    memcpy(&data, &dest, sizeof(SQL_TIMESTAMP_STRUCT));
    if(lengthindicator) {
        *lengthindicator=sizeof(SQL_TIMESTAMP_STRUCT);
    }
    DBUG_RETURN(IFR_OK);

}

//----------------------------------------------------------------------
IFR_Retcode
IFRConversion_ByteCharDataConverter
::translateOutput(IFRPacket_DataPart&      datapart,
                  SQL_NUMERIC_STRUCT&      data,
                  IFR_Length*                lengthindicator,
                  IFR_ConnectionItem      &clink)
{
    DBUG_CLINK_METHOD_ENTER(IFRConversion_ByteCharDataConverter, translateOutput_NUMERIC);
    
    char *buffer = (char *) alloca(m_shortinfo.length + 1);
    moveDataToBuffer(datapart, buffer);
    
    IFR_Retcode rc = IFRUtil_SQLNumeric::asciiStringToNumeric(buffer, data);
    switch(rc) {
    case IFR_NOT_OK:
        clink.error().setRuntimeError(IFR_ERR_INVALID_NUMERIC_VALUE_I, (IFR_Int4)this->m_index);
        break;
    case IFR_OVERFLOW:
        clink.error().setRuntimeError(IFR_ERR_NUMERIC_OVERFLOW_I, (IFR_Int4)this->m_index);
        break;
    default:
        if(*lengthindicator) {
            *lengthindicator = sizeof(SQL_NUMERIC_STRUCT);
        }
    }
    DBUG_RETURN(rc);
}

//----------------------------------------------------------------------
IFR_Retcode
IFRConversion_ByteCharDataConverter
::translateOutput(IFRPacket_DataPart& datapart,
                  GUID&               data,
                  IFR_Length*           lengthindicator,
                  IFR_ConnectionItem &clink)
{
    DBUG_CLINK_METHOD_ENTER(IFRConversion_ByteCharDataConverter, translateOutput_GUID);
    if(m_shortinfo.length < sizeof(GUID)) {
        clink.error().setRuntimeError(IFR_ERR_PARAM_CONVERSION_TRUNCATEDATA_I, (IFR_Int4)this->m_index);
        DBUG_RETURN(IFR_NOT_OK);
    }
    IFR_Retcode rc=translateBinaryOutput(datapart, (char*)&data, sizeof(GUID), lengthindicator, clink);
    if(rc != IFR_OK && rc!=IFR_DATA_TRUNC) {
        DBUG_RETURN(rc);
    } else {
        if(lengthindicator && *lengthindicator > 0) {
            *lengthindicator=sizeof(GUID);
        }
        DBUG_RETURN(IFR_OK);
    }
}

