trailing junk characters in market price data

Reference:

ACT_TP_1 "ACT TYPE 1" 270 ACT_TP_2 ENUMERATED 3 ( 2 ) ENUM 1

similar to
SC_ACT_TP1 "SEC ACT TYPE 1" 280 SC_ACT_TP2 ENUMERATED 3 ( 2 ) ENUM 1

Sample message:
{"RIC":"USDAM3L3Y=","BID":"2.8510","PRIMACT_1":"2.8510","ASK":"2.8610","SEC_ACT_1":"2.8610",

"NETCHNG_1":"0.0019","PCTCHNG":"0.07","ACT_TP_1":"B<DE>(26)","VALUE_DT1":"10 JUL 2018","VALUE_TS1":"20:53:11:000:000:000","SC_ACT_TP1":" A(17)","CTBTR_1":"BROKER ","CTB_LOC1":"GFX","CTB_PAGE1":"BRKR","DLG_CODE1":" "}

SC_ACT_TP1 looks correct whereas ACT_TP_1 contains junk characters


I am doing a simple formatting to parse and print these values:

case RSSL_DT_ENUM:
{
if ((ret = rsslDecodeEnum(dIter, &fidEnumValue)) == RSSL_RET_SUCCESS)
{

RsslEnumType* pEnumType = getFieldEntryEnumType(dictionaryEntry, fidEnumValue);
if (pEnumType)
{

snprintf(m_msg_buf,
sizeof(m_msg_buf),
"\"%.*s(%d)\",",
pEnumType->display.length,
pEnumType->display.data,
fidEnumValue);
m_msg << m_msg_buf;
}

display.length is probably not accurate and hence there is junk trailing characters.
The correct value is B(26) I think

Best Answer

  • @akrishnan

    According to enumtype.def file, the enumeration values of "ACT_TP_1" field are defined as follows.

    !
    ! ACRONYM FID
    ! ------- ---
    !
    ACT_TP_1 270
    ...
    !
    ! VALUE DISPLAY MEANING
    ! ----- ------- -------
    ...
    26 #42DE# bid price, up or zero up tick
    27 #42FE# bid price, down or zero down tick

    The enum values enclosed in “#” are characters encoded in
    Reuters Multi-Lingual Text Encoding Standard (RMTES). You need to use RMTES
    conversion utility to convert the value to UTF-8.

    The "#42DE#" value finally will be converted to 0x 42 e2 87 a7 in UTF-8 displayed as "B⇧".

    image

    Please see the “11.2.9RMTES Decoding” section in UPA Developers
    Guide document for more information. Below is the example code modified from
    the rsslConsumer example application to demonstrate the RMTES conversion.

    rsslMarketPriceHandler.c

    RsslRet decodeFieldEntry(RsslFieldEntry* fEntry, RsslDecodeIterator *dIter)
    {

    case RSSL_DT_ENUM:
    if ((ret = rsslDecodeEnum(dIter, &fidEnumValue)) == RSSL_RET_SUCCESS)
    {
    RsslEnumType *pEnumType = getFieldEntryEnumType(dictionaryEntry, fidEnumValue);
    if (pEnumType)
    {
    /* create cache buffer for storing RMTES and applying partial updates */
    RsslRmtesCacheBuffer rmtesCache;
    char cacheSpace[100];
    /* create RsslBuffer to convert into */
    RsslBuffer utf8Buffer;
    char convertSpace[100];
    int i = 0;
    RsslRet retVal = 0;
    /* populate cache and conversion buffers with created memory */
    rmtesCache.data = cacheSpace;
    rmtesCache.length = 0; /* this is the used length, since cache starts out empty it should start at 0 */
    rmtesCache.allocatedLength = 100;
    utf8Buffer.data = convertSpace;
    utf8Buffer.length = 100;
    /* apply RMTES content to cache, if successful convert to UTF-8 */
    if ((retVal = rsslRMTESApplyToCache(&(pEnumType->display), &rmtesCache)) < RSSL_RET_SUCCESS)
    {
    /* error while applying to cache */
    printf("Error %s (%d) encountered while applying buffer to RMTES cache. Error Text: %s\n",
    rsslRetCodeToString(retVal), retVal, rsslRetCodeInfo(retVal));
    }
    else if ((retVal = rsslRMTESToUTF8(&rmtesCache, &utf8Buffer)) < RSSL_RET_SUCCESS)
    {
    /* error when converting */
    printf("Error %s (%d) encountered while converting from RMTES to UTF-8. Error Text: %s\n",
    rsslRetCodeToString(retVal), retVal, rsslRetCodeInfo(retVal));
    }
    else
    {
    /* SUCCESS: conversion was successful – application can now use converted content */
    for (i = 0; i < utf8Buffer.length; i ++) {
    printf(" %x", (unsigned char)utf8Buffer.data[i]);
    }
    printf("(%d)\n", pEnumType->value);
    }
    }
    else
    printf("%d\n", fidEnumValue);
    }
    else if (ret != RSSL_RET_BLANK_DATA)
    {
    printf("rsslDecodeEnum() failed with return code: %d\n", ret);
    return ret;
    }
    break;

Answers

  • Hi Veerapath,

    Thank you, that resolved the issue.

    I also noticed escape literals in alphanumeric fields as follows:

    DSPLY_NMLL "LCL LANG DSP NM" 1352 NULL ALPHANUMERIC 32 RMTES_STRING 32

    "DSPLY_NMLL":"ESC[0` ESC[31b",

    that is,

    "DSPLY_NMLL":"\x1b[0` \x1b[31b"

    I have in code:

    case RSSL_DT_BUFFER:
    case RSSL_DT_ASCII_STRING:
    case RSSL_DT_UTF8_STRING:

    case RSSL_DT_RMTES_STRING:
    if ((ret = rsslDecodeBuffer(dIter, &fidBufferValue)) == RSSL_RET_SUCCESS)
    {
    snprintf(m_msg_buf, sizeof(m_msg_buf), "\"%.*s\",", fidBufferValue.length, fidBufferValue.data);
    m_msg << m_msg_buf;
    }
    else if (ret != RSSL_RET_BLANK_DATA)
    {
    std::cerr << "rsslDecodeBuffer() failed with return code: " << ret << std::endl;
    return ret;
    }
    break;

    Please can you advise how this needs to be processed?

  • @akrishnan

    The received data could be in Partial Content Update format where only partial content is provided with offset position.

    <0x1B5B><offset position><0x60><partial content>

    For example, "ESC[0` " will update the existing content at offset position 0 with a space.

    To process this data, you can use the RMTES Decoding code, since the rsslRMTESApplyToCache method will apply the partial content update as well. However, you need to store the character buffer for the existing content.

    Below is the sample code.

      static char cacheSpaceForPartial[100];
    ...
    case RSSL_DT_RMTES_STRING:
    //
    if (fEntry->fieldId == 1352)
    {
    if ((ret = rsslDecodeBuffer(dIter, &fidBufferValue)) == RSSL_RET_SUCCESS)
    {
    /* create cache buffer for storing RMTES and applying partial updates */
    RsslRmtesCacheBuffer rmtesCache;
    /* create RsslBuffer to convert into */
    RsslBuffer utf8Buffer;
    char convertSpace[100];
    int i = 0;
    RsslRet retVal = 0;
    if (!rsslHasPartialRMTESUpdate(&fidBufferValue))
    {
    /* populate cache and conversion buffers with created memory */
    rmtesCache.data = cacheSpaceForPartial;
    rmtesCache.length = 0; /* this is the used length, since cache starts out empty it should start at 0 */
    rmtesCache.allocatedLength = 100;
    }
    utf8Buffer.data = convertSpace;
    utf8Buffer.length = 100;
    /* apply RMTES content to cache, if successful convert to UTF-8 */
    if ((retVal = rsslRMTESApplyToCache(&fidBufferValue, &rmtesCache)) < RSSL_RET_SUCCESS)
    {
    /* error while applying to cache */
    printf("Error %s (%d) encountered while applying buffer to RMTES cache. Error Text: %s\n",
    rsslRetCodeToString(retVal), retVal, rsslRetCodeInfo(retVal));
    }
    else if ((retVal = rsslRMTESToUTF8(&rmtesCache, &utf8Buffer)) < RSSL_RET_SUCCESS)
    {
    /* error when converting */
    printf("Error %s (%d) encountered while converting from RMTES to UTF-8. Error Text: %s\n",
    rsslRetCodeToString(retVal), retVal, rsslRetCodeInfo(retVal));
    }
    else
    {
    /* SUCCESS: conversion was successful – application can now use converted content */
    for (i = 0; i < utf8Buffer.length; i++) {
    printf("%c", (unsigned char)utf8Buffer.data[i]);
    }
    printf("\n");
    }
    }
    }