/* ISO8583.h */
/* Create by jojoke */
#ifndef __ISO_8583_H__
#define __ISO_8583_H__
#include < map >
using namespace std;
typedef struct
{
int bit_flag; /* 域数据类型0 -- string, 1 -- int, 2 -- binary */
char * data_name; /* 域名 */
int length; /* 数据域长度 */
int length_in_byte; /* 实际长度(如果是变长) */
int variable_flag; /* 是否变长标志0:否 2:2位变长, 3:3位变长 */
int datatype; /* 0 -- string, 1 -- int, 2 -- binary */
char * data; /* 存放具体值 */
int attribute; /* 保留 */
} ISO8583Field;
typedef struct {
int len;
BYTE * data;
} ISO8583FieldData;
class CISO8583
{
public :
enum FileType
{
XML,
BIN,
HEX
};
/* Get message length in bytes */
int GetMessageLength();
/* Write message out in xml format */
virtual bool WriteToFile(LPCTSTR pszFile, FileType type);
protected :
bool writeXML(LPCTSTR pszXMLFile);
bool writeBIN(LPCTSTR pszBINFile);
bool writeHEX(LPCTSTR pszHEXFile);
void setBit(BYTE * pBytes, int nPos);
bool testBit( const BYTE * pBytes, int nPos);
map < int , ISO8583FieldData > m_fields;
};
class CISO8583Writer : public CISO8583
{
public :
CISO8583Writer();
~ CISO8583Writer();
/* Copy message out */
int CopyOut(BYTE * pOutBuf, int nBufLen);
/* write specified field, if pFieldBuf is NULL then this field will be cleared */
const BYTE * WriteField( int nField, int nFieldLen, BYTE * pFieldBuf);
};
class CISO8583Reader : public CISO8583
{
public :
CISO8583Reader();
~ CISO8583Reader();
/* Read the message */
bool ReadMessage( const BYTE * pMessage);
/* Get field data */
int GetFields( int * fields, int count);
/* Findout whether specified field exists */
bool FieldExist( int nField);
/* Findout whether specified fields exist. */
int FieldsExist( int * fields, int nCount);
/* Get fields total count */
int FieldsCount();
/* Get specified field length */
int FieldLength( int nField);
/* Get specified field data */
int ReadField( int nField, BYTE * pOutBuf, int nBufLen);
protected :
bool parseFields( const BYTE * pMessage);
};
#endif
#define __ISO_8583_H__
#include < map >
using namespace std;
typedef struct
{
int bit_flag; /* 域数据类型0 -- string, 1 -- int, 2 -- binary */
char * data_name; /* 域名 */
int length; /* 数据域长度 */
int length_in_byte; /* 实际长度(如果是变长) */
int variable_flag; /* 是否变长标志0:否 2:2位变长, 3:3位变长 */
int datatype; /* 0 -- string, 1 -- int, 2 -- binary */
char * data; /* 存放具体值 */
int attribute; /* 保留 */
} ISO8583Field;
typedef struct {
int len;
BYTE * data;
} ISO8583FieldData;
class CISO8583
{
public :
enum FileType
{
XML,
BIN,
HEX
};
/* Get message length in bytes */
int GetMessageLength();
/* Write message out in xml format */
virtual bool WriteToFile(LPCTSTR pszFile, FileType type);
protected :
bool writeXML(LPCTSTR pszXMLFile);
bool writeBIN(LPCTSTR pszBINFile);
bool writeHEX(LPCTSTR pszHEXFile);
void setBit(BYTE * pBytes, int nPos);
bool testBit( const BYTE * pBytes, int nPos);
map < int , ISO8583FieldData > m_fields;
};
class CISO8583Writer : public CISO8583
{
public :
CISO8583Writer();
~ CISO8583Writer();
/* Copy message out */
int CopyOut(BYTE * pOutBuf, int nBufLen);
/* write specified field, if pFieldBuf is NULL then this field will be cleared */
const BYTE * WriteField( int nField, int nFieldLen, BYTE * pFieldBuf);
};
class CISO8583Reader : public CISO8583
{
public :
CISO8583Reader();
~ CISO8583Reader();
/* Read the message */
bool ReadMessage( const BYTE * pMessage);
/* Get field data */
int GetFields( int * fields, int count);
/* Findout whether specified field exists */
bool FieldExist( int nField);
/* Findout whether specified fields exist. */
int FieldsExist( int * fields, int nCount);
/* Get fields total count */
int FieldsCount();
/* Get specified field length */
int FieldLength( int nField);
/* Get specified field data */
int ReadField( int nField, BYTE * pOutBuf, int nBufLen);
protected :
bool parseFields( const BYTE * pMessage);
};
#endif
/* ISO8583.cpp */
/* Create by jojoke */
#include
"
StdAfx.h
"
#include " ISO8583.h "
#include " math.h "
#include " assert.h "
ISO8583Field Tbl8583[ 128 ] =
{
/* FLD 01 */ { 0 , " BIT MAP,EXTENDED " , 8 , 0 , 0 , 2 , NULL, 0 },
/* FLD 02 */ { 0 , " PRIMARY ACCOUNT NUMBER " , 22 , 0 , 2 , 0 , NULL, 0 },
/* FLD 03 */ { 0 , " PROCESSING CODE " , 6 , 0 , 0 , 0 , NULL, 0 },
/* FLD 04 */ { 0 , " AMOUNT, TRANSACTION " , 12 , 0 , 0 , 1 , NULL, 0 },
/* FLD 05 */ { 0 , " NO USE " , 12 , 0 , 0 , 0 , NULL, 0 },
/* FLD 06 */ { 0 , " NO USE " , 12 , 0 , 0 , 0 , NULL, 0 },
/* FLD 07 */ { 0 , " TRANSACTION DATE AND TIME " , 10 , 0 , 0 , 0 , NULL, 0 },
/* FLD 08 */ { 0 , " NO USE " , 8 , 0 , 0 , 0 , NULL, 0 },
/* FLD 09 */ { 0 , " NO USE " , 8 , 0 , 0 , 0 , NULL, 0 },
/* FLD 10 */ { 0 , " NO USE " , 8 , 0 , 0 , 0 , NULL, 0 },
/* FLD 11 */ { 0 , " SYSTEM TRACE AUDIT NUMBER " , 6 , 0 , 0 , 1 , NULL, 0 },
/* FLD 12 */ { 0 , " TIME, LOCAL TRANSACTION " , 6 , 0 , 0 , 0 , NULL, 0 },
/* FLD 13 */ { 0 , " DATE, LOCAL TRANSACTION " , 4 , 0 , 0 , 0 , NULL, 0 },
/* FLD 14 */ { 0 , " DATE, EXPIRATION " , 4 , 0 , 0 , 0 , NULL, 0 },
/* FLD 15 */ { 0 , " DATE, SETTLEMENT " , 4 , 0 , 0 , 0 , NULL, 0 },
/* FLD 16 */ { 0 , " NO USE " , 4 , 0 , 0 , 0 , NULL, 0 },
/* FLD 17 */ { 0 , " DATE, CAPTURE " , 4 , 0 , 0 , 0 , NULL, 0 },
/* FLD 18 */ { 0 , " MERCHANT'S TYPE " , 4 , 0 , 0 , 0 , NULL, 0 },
/* FLD 19 */ { 0 , " NO USE " , 3 , 0 , 0 , 0 , NULL, 0 },
/* FLD 20 */ { 0 , " NO USE " , 3 , 0 , 0 , 0 , NULL, 0 },
/* FLD 21 */ { 0 , " NO USE " , 3 , 0 , 0 , 0 , NULL, 0 },
/* FLD 22 */ { 0 , " POINT OF SERVICE ENTRY MODE " , 3 , 0 , 0 , 0 , NULL, 0 },
/* FLD 23 */ { 0 , " NO USE " , 3 , 0 , 0 , 0 , NULL, 0 },
/* FLD 24 */ { 0 , " NO USE " , 3 , 0 , 0 , 0 , NULL, 0 },
/* FLD 25 */ { 0 , " POINT OF SERVICE CONDITION CODE " , 2 , 0 , 0 , 0 , NULL, 0 },
/* FLD 26 */ { 0 , " NO USE " , 2 , 0 , 0 , 0 , NULL, 0 },
/* FLD 27 */ { 0 , " NO USE " , 1 , 0 , 0 , 0 , NULL, 0 },
/* FLD 28 */ { 0 , " field27 " , 6 , 0 , 0 , 0 , NULL, 0 },
/* FLD 29 */ { 0 , " NO USE " , 8 , 0 , 1 , 0 , NULL, 0 },
/* FLD 30 */ { 0 , " NO USE " , 8 , 0 , 1 , 0 , NULL, 0 },
/* FLD 31 */ { 0 , " NO USE " , 8 , 0 , 1 , 0 , NULL, 0 },
/* FLD 32 */ { 0 , " ACQUIRER INSTITUTION ID. CODE " , 11 , 0 , 2 , 0 , NULL, 0 },
/* FLD 33 */ { 0 , " FORWARDING INSTITUTION ID. CODE " , 11 , 0 , 2 , 0 , NULL, 0 },
/* FLD 34 */ { 0 , " NO USE " , 28 , 0 , 2 , 0 , NULL, 0 },
/* FLD 35 */ { 0 , " TRACK 2 DATA " , 37 , 0 , 2 , 0 , NULL, 0 },
/* FLD 36 */ { 0 , " TRACK 3 DATA " , 104 , 0 , 3 , 0 , NULL, 0 },
/* FLD 37 */ { 0 , " RETRIEVAL REFERENCE NUMBER " , 12 , 0 , 0 , 0 , NULL, 0 },
/* FLD 38 */ { 0 , " AUTH. IDENTIFICATION RESPONSE " , 6 , 0 , 0 , 0 , NULL, 0 },
/* FLD 39 */ { 0 , " RESPONSE CODE " , 2 , 0 , 0 , 0 , NULL, 0 },
/* FLD 40 */ { 0 , " NO USE " , 3 , 0 , 0 , 0 , NULL, 0 },
/* FLD 41 */ { 0 , " CARD ACCEPTOR TERMINAL ID. " , 8 , 0 , 0 , 0 , NULL, 0 },
/* FLD 42 */ { 0 , " CARD ACCEPTOR IDENTIFICATION CODE " , 15 , 0 , 0 , 0 , NULL, 0 },
/* FLD 43 */ { 0 , " CARD ACCEPTOR NAME LOCATION " , 40 , 0 , 0 , 0 , NULL, 0 },
/* FLD 44 */ { 0 , " ADDITIONAL RESPONSE DATA " , 25 , 0 , 2 , 0 , NULL, 0 },
/* FLD 45 */ { 0 , " NO USE " , 76 , 0 , 2 , 0 , NULL, 0 },
/* FLD 46 */ { 0 , " NO USE " , 999 , 0 , 3 , 0 , NULL, 0 },
/* FLD 47 */ { 0 , " field47 " , 999 , 0 , 3 , 0 , NULL, 0 },
/* FLD 48 */ { 0 , " ADDITIONAL DATA --- PRIVATE " , 999 , 0 , 3 , 0 , NULL, 0 },
/* FLD 49 */ { 0 , " CURRENCY CODE,TRANSACTION " , 3 , 0 , 0 , 0 , NULL, 0 },
/* FLD 50 */ { 0 , " CURRENCY CODE,SETTLEMENT " , 3 , 0 , 0 , 0 , NULL, 0 },
/* FLD 51 */ { 0 , " NO USE " , 3 , 0 , 0 , 0 , NULL, 0 },
/* FLD 52 */ { 0 , " PERSONAL IDENTIFICATION NUMBER DATA " , 8 , 0 , 0 , 2 , NULL, 0 },
/* FLD 53 */ { 0 , " SECURITY RELATED CONTROL INformATION " , 16 , 0 , 0 , 0 , NULL, 0 },
/* FLD 54 */ { 0 , " ADDITIONAL AMOUNTS " , 120 , 0 , 3 , 0 , NULL, 0 },
/* FLD 55 */ { 0 , " NO USE " , 999 , 0 , 3 , 0 , NULL, 0 },
/* FLD 56 */ { 0 , " NO USE " , 999 , 0 , 3 , 0 , NULL, 0 },
/* FLD 57 */ { 0 , " NO USE " , 999 , 0 , 3 , 0 , NULL, 0 },
/* FLD 58 */ { 0 , " NO USE " , 999 , 0 , 3 , 0 , NULL, 0 },
/* FLD 59 */ { 0 , " NO USE " , 999 , 0 , 3 , 0 , NULL, 0 },
/* FLD 60 */ { 0 , " NO USE " , 999 , 0 , 3 , 0 , NULL, 0 },
/* FLD 61 */ { 0 , " NO USE " , 999 , 0 , 3 , 0 , NULL, 0 },
/* FLD 62 */ { 0 , " NO USE " , 999 , 0 , 3 , 0 , NULL, 0 },
/* FLD 63 */ { 0 , " NO USE " , 999 , 0 , 3 , 0 , NULL, 0 },
/* FLD 64 */ { 0 , " MESSAGE AUTHENTICATION CODE FIELD " , 8 , 0 , 0 , 2 , NULL, 0 },
/* FLD 65 */ { 0 , " NO USE " , 999 , 0 , 3 , 0 , NULL, 0 },
/* FLD 66 */ { 0 , " NO USE " , 1 , 0 , 0 , 0 , NULL, 0 },
/* FLD 67 */ { 0 , " NO USE " , 999 , 0 , 3 , 0 , NULL, 0 },
/* FLD 68 */ { 0 , " NO USE " , 999 , 0 , 3 , 0 , NULL, 0 },
/* FLD 69 */ { 0 , " NO USE " , 999 , 0 , 3 , 0 , NULL, 0 },
/* FLD 70 */ { 0 , " SYSTEM MANAGEMENT INformATION CODE " , 3 , 0 , 0 , 0 , NULL, 0 },
/* FLD 71 */ { 0 , " NO USE " , 999 , 0 , 3 , 0 , NULL, 0 },
/* FLD 72 */ { 0 , " NO USE " , 999 , 0 , 3 , 0 , NULL, 0 },
/* FLD 73 */ { 0 , " NO USE " , 6 , 0 , 0 , 0 , NULL, 0 },
/* FLD 74 */ { 0 , " NUMBER OF CREDITS " , 10 , 0 , 0 , 0 , NULL, 0 },
/* FLD 75 */ { 0 , " REVERSAL NUMBER OF CREDITS " , 10 , 0 , 0 , 0 , NULL, 0 },
/* FLD 76 */ { 0 , " NUMBER OF DEBITS " , 10 , 0 , 0 , 0 , NULL, 0 },
/* FLD 77 */ { 0 , " REVERSAL NUMBER OF DEBITS " , 10 , 0 , 0 , 0 , NULL, 0 },
/* FLD 78 */ { 0 , " NUMBER OF TRANSFER " , 10 , 0 , 0 , 0 , NULL, 0 },
/* FLD 79 */ { 0 , " REVERSAL NUMBER OF TRANSFER " , 10 , 0 , 0 , 0 , NULL, 0 },
/* FLD 80 */ { 0 , " NUMBER OF INQUIRS " , 10 , 0 , 0 , 0 , NULL, 0 },
/* FLD 81 */ { 0 , " AUTHORIZATION NUMBER " , 10 , 0 , 0 , 0 , NULL, 0 },
/* FLD 82 */ { 0 , " NO USE " , 12 , 0 , 0 , 0 , NULL, 0 },
/* FLD 83 */ { 0 , " CREDITS,TRANSCATION FEEAMOUNT " , 12 , 0 , 0 , 0 , NULL, 0 },
/* FLD 84 */ { 0 , " NO USE " , 12 , 0 , 0 , 0 , NULL, 0 },
/* FLD 85 */ { 0 , " DEBITS,TRANSCATION FEEAMOUNT " , 12 , 0 , 0 , 0 , NULL, 0 },
/* FLD 86 */ { 0 , " AMOUNT OF CREDITS " , 16 , 0 , 0 , 0 , NULL, 0 },
/* FLD 87 */ { 0 , " REVERSAL AMOUNT OF CREDITS " , 16 , 0 , 0 , 0 , NULL, 0 },
/* FLD 88 */ { 0 , " AMOUNT OF DEBITS " , 16 , 0 , 0 , 0 , NULL, 0 },
/* FLD 89 */ { 0 , " REVERSAL AMOUNT OF DEBITS " , 16 , 0 , 0 , 0 , NULL, 0 },
/* FLD 90 */ { 0 , " ORIGINAL DATA ELEMENTS " , 42 , 0 , 0 , 0 , NULL, 0 },
/* FLD 91 */ { 0 , " FILE UPDATE CODE " , 1 , 0 , 0 , 0 , NULL, 0 },
/* FLD 92 */ { 0 , " NO USE " , 999 , 0 , 3 , 0 , NULL, 0 },
/* FLD 93 */ { 0 , " NO USE " , 999 , 0 , 3 , 0 , NULL, 0 },
/* FLD 94 */ { 0 , " SERVICE INDICATOR " , 7 , 0 , 0 , 0 , NULL, 0 },
/* FLD 95 */ { 0 , " REPLACEMENT AMOUNTS " , 42 , 0 , 0 , 0 , NULL, 0 },
/* FLD 96 */ { 0 , " NO USE " , 8 , 0 , 0 , 0 , NULL, 0 },
/* FLD 97 */ { 0 , " AMOUNT OF NET SETTLEMENT " , 16 , 0 , 0 , 0 , NULL, 0 },
/* FLD 98 */ { 0 , " NO USE " , 999 , 0 , 3 , 0 , NULL, 0 },
/* FLD 99 */ { 0 , " SETTLEMENT INSTITUTION ID " , 11 , 0 , 2 , 0 , NULL, 0 },
/* FLD 100 */ { 0 , " RECVEING INSTITUTION ID " , 11 , 0 , 2 , 0 , NULL, 0 },
/* FLD 101 */ { 0 , " FILENAME " , 17 , 0 , 2 , 0 , NULL, 0 },
/* FLD 102 */ { 0 , " ACCOUNT IDENTIFICATION1 " , 28 , 0 , 2 , 0 , NULL, 0 },
/* FLD 103 */ { 0 , " ACCOUNT IDENTIFICATION2 " , 28 , 0 , 2 , 0 , NULL, 0 },
/* FLD 104 */ { 0 , " NO USE " , 999 , 0 , 3 , 0 , NULL, 0 },
/* FLD 105 */ { 0 , " NO USE " , 999 , 0 , 3 , 0 , NULL, 0 },
/* FLD 106 */ { 0 , " NO USE " , 999 , 0 , 3 , 0 , NULL, 0 },
/* FLD 107 */ { 0 , " NO USE " , 999 , 0 , 3 , 0 , NULL, 0 },
/* FLD 108 */ { 0 , " NO USE " , 999 , 0 , 3 , 0 , NULL, 0 },
/* FLD 109 */ { 0 , " NO USE " , 999 , 0 , 3 , 0 , NULL, 0 },
/* FLD 110 */ { 0 , " NO USE " , 999 , 0 , 3 , 0 , NULL, 0 },
/* FLD 111 */ { 0 , " NO USE " , 999 , 0 , 3 , 0 , NULL, 0 },
/* FLD 112 */ { 0 , " NO USE " , 999 , 0 , 3 , 0 , NULL, 0 },
/* FLD 113 */ { 0 , " NO USE " , 999 , 0 , 3 , 0 , NULL, 0 },
/* FLD 114 */ { 0 , " NO USE " , 999 , 0 , 3 , 0 , NULL, 0 },
/* FLD 115 */ { 0 , " NO USE " , 999 , 0 , 3 , 0 , NULL, 0 },
/* FLD 116 */ { 0 , " NO USE " , 999 , 0 , 3 , 0 , NULL, 0 },
/* FLD 117 */ { 0 , " NO USE " , 999 , 0 , 3 , 0 , NULL, 0 },
/* FLD 118 */ { 0 , " NO USE " , 999 , 0 , 3 , 0 , NULL, 0 },
/* FLD 119 */ { 0 , " NO USE " , 999 , 0 , 3 , 0 , NULL, 0 },
/* FLD 120 */ { 0 , " NO USE " , 999 , 0 , 3 , 0 , NULL, 0 },
/* FLD 121 */ { 0 , " NO USE " , 999 , 0 , 3 , 0 , NULL, 0 },
/* FLD 122 */ { 0 , " NO USE " , 999 , 0 , 3 , 0 , NULL, 0 },
/* FLD 123 */ { 0 , " NEW PIN DATA " , 8 , 0 , 3 , 2 , NULL, 0 },
/* FLD 124 */ { 0 , " NO USE " , 999 , 0 , 3 , 0 , NULL, 0 },
/* FLD 125 */ { 0 , " NO USE " , 999 , 0 , 3 , 0 , NULL, 0 },
/* FLD 126 */ { 0 , " NO USE " , 999 , 0 , 3 , 0 , NULL, 0 },
/* FLD 127 */ { 0 , " NO USE " , 999 , 0 , 3 , 0 , NULL, 0 },
/* FLD 128 */ { 0 , " MESSAGE AUTHENTICATION CODE FIELD " , 8 , 0 , 0 , 2 , NULL, 0 },
};
/* Set bit in specified position */
void CISO8583::setBit(BYTE * pBytes, int nPos)
{
if (nPos % 8 == 0 )
pBytes[nPos / 8 - 1 ] |= 0x01 ;
else
pBytes[(unsigned int )floor(nPos / 8 )] |= ( 0x80 >> (nPos % 8 - 1 ));
if (nPos > 64 )
setBit(pBytes, 1 );
}
/* Test to see if bit position of p is set */
bool CISO8583::testBit( const BYTE * pBytes, int nPos)
{
unsigned int nOffset;
BYTE nMask;
nOffset = nPos % 8 == 0 ? nPos / 8 - 1 : (unsigned int )floor(nPos / 8 );
nMask = nPos % 8 == 0 ? 0x01 : ( 0x80 >> (nPos % 8 - 1 ));
return (pBytes[nOffset] & nMask) == nMask;
}
/* Write message in xml format */
bool CISO8583::writeXML(LPCTSTR pszXMLFile)
{
int i = 0 ;
BYTE bitmap[ 16 ];
char sBitMap[ 33 ] = { ' \0 ' };
TCHAR * szFieldType[ 3 ] = { " string " , " int " , " binary " };
FILE * fp = fopen(pszXMLFile, " w " );
if (NULL == fp)
return false ;
/* write bitmap */
memset(bitmap, 0 , sizeof (bitmap));
map < int , ISO8583FieldData > ::iterator it = m_fields.begin();
while (it != m_fields.end()) {
setBit(bitmap, it -> first);
it ++ ;
}
for (i = 0 ; i < 16 ; i ++ )
_snprintf(sBitMap + 2 * i, 2 , " %02x " , bitmap[i]);
fprintf(fp, " <?xml version=\ " 1.0 \ " encoding=\ " GB2312\ " ?>\r\n " );
fprintf(fp, " <ISO8583 fieldscount=\ " % d\ " totalbytes=\ " % d\ " bitmap=\ " % s\ " > " , m_fields.size(), this -> GetMessageLength(), sBitMap);
/* write fields */
it = m_fields.begin();
while (it != m_fields.end()) {
fprintf(fp, " \r\n\t<Field no=\ " % d\ " type=\ " % s\ " fieldlength=\ " % d\ " datalength=\ " % d\ " >\n " , it -> first, szFieldType[Tbl8583[it -> first - 1 ].datatype], Tbl8583[it -> first - 1 ].length, it -> second.len);
if (Tbl8583[it -> first - 1 ].datatype == 1 )
fprintf(fp, " \t\t%s " , ( char * )it -> second.data);
else {
fprintf(fp, " \t\t " );
for (i = 0 ; i < it -> second.len; i ++ )
fprintf(fp, " %02X " , (BYTE)it -> second.data[i]);
}
fprintf(fp, " \n\t</Field> " );
it ++ ;
}
fprintf(fp, " \n</ISO8583> " );
fclose(fp);
return true ;
}
bool CISO8583::writeBIN(LPCTSTR pszBINFile)
{
int i = 0 ;
BYTE bitmap[ 16 ];
FILE * fp = fopen(pszBINFile, " wb " );
if (NULL == fp)
return false ;
/* write bitmap */
memset(bitmap, 0 , sizeof (bitmap));
map < int , ISO8583FieldData > ::iterator it = m_fields.begin();
while (it != m_fields.end()) {
setBit(bitmap, it -> first);
it ++ ;
}
fwrite(bitmap, 1 , sizeof (bitmap), fp);
/* write fields */
it = m_fields.begin();
while (it != m_fields.end()) {
if (Tbl8583[it -> first - 1 ].variable_flag == 0 )
fwrite(it -> second.data, 1 , it -> second.len, fp);
else if (Tbl8583[it -> first - 1 ].variable_flag == 2 ) {
fprintf(fp, " %02d " , it -> second.len);
fwrite(it -> second.data, 1 , it -> second.len, fp);
}
else if (Tbl8583[it -> first - 1 ].variable_flag == 3 ) {
fprintf(fp, " %03d " , it -> second.len);
fwrite(it -> second.data, 1 , it -> second.len, fp);
}
it ++ ;
}
fclose(fp);
return true ;
}
bool CISO8583::writeHEX(LPCTSTR pszHEXFile)
{
int i = 0 , j = 0 , round = 0 , length = this -> GetMessageLength();
FILE * fp = fopen(pszHEXFile, " wb " );
if (NULL == fp)
return false ;
BYTE * pBytes = new BYTE[length];
BYTE * p = pBytes;
if (NULL == pBytes)
return false ;
memset(pBytes, 0 , length);
/* write bitmap */
map < int , ISO8583FieldData > ::iterator it = m_fields.begin();
while (it != m_fields.end()) {
setBit(pBytes, it -> first);
it ++ ;
}
p += 16 ;
/* write fields */
it = m_fields.begin();
while (it != m_fields.end()) {
if (Tbl8583[it -> first - 1 ].variable_flag == 0 ) {
memcpy(p, it -> second.data, it -> second.len);
}
else if (Tbl8583[it -> first - 1 ].variable_flag == 2 ) {
_snprintf(( char * )p, 2 , " %02d " , it -> second.len);
p += 2 ;
memcpy(p, it -> second.data, it -> second.len);
}
else if (Tbl8583[it -> first - 1 ].variable_flag == 3 ) {
_snprintf(( char * )p, 3 , " %03d " , it -> second.len);
p += 3 ;
memcpy(p, it -> second.data, it -> second.len);
}
p += it -> second.len;
it ++ ;
}
/* write to file in ultraedit hex-view format */
for (i = 0 ; i < length; i ++ ) {
if (i == 0 )
fprintf(fp, " %08Xh: " , round);
fprintf(fp, " %02X " , pBytes[i]);
if ( ++ round % 16 == 0 && i != length - 1 ) {
fwrite( " ; " , 1 , 3 , fp);
p = pBytes + i - 15 ;
for (j = 0 ; j < 16 ; j ++ )
fprintf(fp, " %c " , (p[j] == 0 || p[j] == ' \r ' || p[j] == ' \n ' ) ? ' . ' : p[j]);
fprintf(fp, " \r\n%08Xh: " , round);
}
}
if ((round = length % 16 ) != 0 ) {
for (i = 0 ; i < 16 - round; i ++ )
fwrite( " " , 1 , 3 , fp);
fwrite( " ; " , 1 , 3 , fp);
p = pBytes + length - round;
for (i = 0 ; i < round; i ++ )
fprintf(fp, " %c " , (p[i] == 0 || p[i] == ' \r ' || p[i] == ' \n ' ) ? ' . ' : p[i]);
}
delete pBytes;
fclose(fp);
return true ;
}
bool CISO8583::WriteToFile(LPCTSTR pszFile, FileType type)
{
if (type == CISO8583::XML)
return writeXML(pszFile);
else if (type == CISO8583::BIN)
return writeBIN(pszFile);
else if (type == CISO8583::HEX)
return writeHEX(pszFile);
return false ;
}
/* Get message length in bytes */
int CISO8583::GetMessageLength()
{
int len = 0 ;
map < int , ISO8583FieldData > ::iterator it = m_fields.begin();
while (it != m_fields.end()) {
len = len + it -> second.len + Tbl8583[it -> first - 1 ].variable_flag;
it ++ ;
}
return len + 16 ;
}
CISO8583Writer::CISO8583Writer()
{
}
CISO8583Writer:: ~ CISO8583Writer()
{
map < int , ISO8583FieldData > ::iterator it = m_fields.begin();
while (it != m_fields.end()) {
delete it -> second.data;
it ++ ;
}
}
/* Copy message out */
int CISO8583Writer::CopyOut(BYTE * pOutBuf, int nBufLen)
{
int offset = 16 ;
if (NULL == pOutBuf || nBufLen < GetMessageLength())
return - 1 ;
/* clear bitmap */
memset(( void * )pOutBuf, 0 , 16 );
map < int , ISO8583FieldData > ::iterator it = m_fields.begin();
while (it != m_fields.end()) {
/* set bitmap */
setBit(pOutBuf, it -> first);
/* copy data */
if (Tbl8583[it -> first - 1 ].variable_flag == 0 ) {
memcpy(pOutBuf + offset, it -> second.data, it -> second.len);
offset += it -> second.len;
}
else if (Tbl8583[it -> first - 1 ].variable_flag == 2 ) {
_snprintf(( char * )(pOutBuf + offset), 2 , " %02d " , it -> second.len);
memcpy(pOutBuf + offset + 2 , it -> second.data, it -> second.len);
offset = offset + it -> second.len + 2 ;
}
else if (Tbl8583[it -> first - 1 ].variable_flag == 3 ) {
_snprintf(( char * )(pOutBuf + offset), 3 , " %03d " , it -> second.len);
memcpy(pOutBuf + offset + 3 , it -> second.data, it -> second.len);
offset = offset + it -> second.len + 3 ;
}
it ++ ;
}
return offset;
}
/* write specified field, if pFieldBuf is NULL then this field will be cleared */
const BYTE * CISO8583Writer::WriteField( int nField, int nFieldLen, BYTE * pFieldBuf)
{
if (nField > 128 || nField < 1 )
throw " field should between 1 and 128 " ;
map < int , ISO8583FieldData > ::iterator it = m_fields.find(nField);
/* delete the specified field if it exists */
if (it != m_fields.end()) {
delete it -> second.data;
m_fields.erase(it);
}
/* clear the specified field and return if pFieldBuf is NULL */
if (NULL == pFieldBuf)
return NULL;
/* copy data */
ISO8583FieldData field;
field.len = nFieldLen;
field.data = new BYTE[field.len];
if (NULL == field.data)
return NULL;
memcpy(field.data, pFieldBuf, field.len);
/* add field */
m_fields[nField] = field;
return field.data;
}
CISO8583Reader::CISO8583Reader()
{
}
CISO8583Reader:: ~ CISO8583Reader()
{
m_fields.clear();
}
bool CISO8583Reader::ReadMessage( const BYTE * pMessage)
{
try {
return parseFields(pMessage);
}
catch () {
return false ;
}
}
/* Get position and length for each field */
bool CISO8583Reader::parseFields( const BYTE * pMessage)
{
bool extensionMode = testBit(pMessage, 1 );
DWORD dwOffset = 16 ;
BYTE len[ 4 ];
/* Test bit pos 2 - 128 or 2 - 64 */
for ( int i = 2 ; i <= 128 && extensionMode; i ++ ) {
if ( ! testBit(pMessage, i)) continue ;
/* find data position and length for each field */
ISO8583FieldData field;
if (Tbl8583[i - 1 ].variable_flag == 0 ) {
field.len = Tbl8583[i - 1 ].length;
field.data = (BYTE * )pMessage + dwOffset;
dwOffset += field.len;
}
else {
memset(len, 0 , sizeof (len));
memcpy(( void * )len, ( void * )(pMessage + dwOffset), Tbl8583[i - 1 ].variable_flag);
field.len = atol(( char * )len);
field.data = (BYTE * )(pMessage + dwOffset + Tbl8583[i - 1 ].variable_flag);
dwOffset = dwOffset + field.len + Tbl8583[i - 1 ].variable_flag;
}
m_fields[i] = field;
}
return true ;
}
/* Get fields number that is set in the bitmap, count should large than value return by FieldsCount() */
int CISO8583Reader::GetFields( int * fields, int count)
{
int fcount = m_fields.size() > count ? count : m_fields.size();
map < int , ISO8583FieldData > ::iterator it = m_fields.begin();
for ( int i = 0 ; i < fcount; i ++ ) {
fields[i] = it -> first;
it ++ ;
}
return fcount;
}
/* Get fields count */
int CISO8583Reader::FieldsCount()
{
return m_fields.size();
}
/* Find to see whether the specified field exist */
bool CISO8583Reader::FieldExist( int nField)
{
return m_fields.find(nField) != m_fields.end();
}
/* Find to see whether all fields in pFields array exist */
int CISO8583Reader::FieldsExist( int * fields, int nCount)
{
for ( int i = 0 ; i < nCount; i ++ ) {
if ( ! FieldExist(fields[i]))
return fields[i];
}
return 0 ;
}
/* Get field length exclusive the LLLVAR or LLVAR part */
int CISO8583Reader::FieldLength( int nField)
{
if (nField > 128 ) return - 1 ;
map < int , ISO8583FieldData > ::iterator it = m_fields.find(nField);
if (it == m_fields.end())
return - 1 ;
/* substract the LLL or LL length */
return it -> second.len - Tbl8583[nField - 1 ].variable_flag;
}
/* Get Field's data, not include the LL or LLL length value if it is varlength field */
int CISO8583Reader::ReadField( int nField, BYTE * pOutBuf, int nBufLen)
{
map < int , ISO8583FieldData > ::iterator it = m_fields.find(nField);
if (it == m_fields.end())
return - 1 ;
int nFieldLen = it -> second.len; // - Tbl8583[nField - 1].variable_flag;
if (nBufLen < it -> second.len)
return - 1 ;
memcpy(pOutBuf, it -> second.data, nFieldLen);
return nFieldLen;
}
#include " ISO8583.h "
#include " math.h "
#include " assert.h "
ISO8583Field Tbl8583[ 128 ] =
{
/* FLD 01 */ { 0 , " BIT MAP,EXTENDED " , 8 , 0 , 0 , 2 , NULL, 0 },
/* FLD 02 */ { 0 , " PRIMARY ACCOUNT NUMBER " , 22 , 0 , 2 , 0 , NULL, 0 },
/* FLD 03 */ { 0 , " PROCESSING CODE " , 6 , 0 , 0 , 0 , NULL, 0 },
/* FLD 04 */ { 0 , " AMOUNT, TRANSACTION " , 12 , 0 , 0 , 1 , NULL, 0 },
/* FLD 05 */ { 0 , " NO USE " , 12 , 0 , 0 , 0 , NULL, 0 },
/* FLD 06 */ { 0 , " NO USE " , 12 , 0 , 0 , 0 , NULL, 0 },
/* FLD 07 */ { 0 , " TRANSACTION DATE AND TIME " , 10 , 0 , 0 , 0 , NULL, 0 },
/* FLD 08 */ { 0 , " NO USE " , 8 , 0 , 0 , 0 , NULL, 0 },
/* FLD 09 */ { 0 , " NO USE " , 8 , 0 , 0 , 0 , NULL, 0 },
/* FLD 10 */ { 0 , " NO USE " , 8 , 0 , 0 , 0 , NULL, 0 },
/* FLD 11 */ { 0 , " SYSTEM TRACE AUDIT NUMBER " , 6 , 0 , 0 , 1 , NULL, 0 },
/* FLD 12 */ { 0 , " TIME, LOCAL TRANSACTION " , 6 , 0 , 0 , 0 , NULL, 0 },
/* FLD 13 */ { 0 , " DATE, LOCAL TRANSACTION " , 4 , 0 , 0 , 0 , NULL, 0 },
/* FLD 14 */ { 0 , " DATE, EXPIRATION " , 4 , 0 , 0 , 0 , NULL, 0 },
/* FLD 15 */ { 0 , " DATE, SETTLEMENT " , 4 , 0 , 0 , 0 , NULL, 0 },
/* FLD 16 */ { 0 , " NO USE " , 4 , 0 , 0 , 0 , NULL, 0 },
/* FLD 17 */ { 0 , " DATE, CAPTURE " , 4 , 0 , 0 , 0 , NULL, 0 },
/* FLD 18 */ { 0 , " MERCHANT'S TYPE " , 4 , 0 , 0 , 0 , NULL, 0 },
/* FLD 19 */ { 0 , " NO USE " , 3 , 0 , 0 , 0 , NULL, 0 },
/* FLD 20 */ { 0 , " NO USE " , 3 , 0 , 0 , 0 , NULL, 0 },
/* FLD 21 */ { 0 , " NO USE " , 3 , 0 , 0 , 0 , NULL, 0 },
/* FLD 22 */ { 0 , " POINT OF SERVICE ENTRY MODE " , 3 , 0 , 0 , 0 , NULL, 0 },
/* FLD 23 */ { 0 , " NO USE " , 3 , 0 , 0 , 0 , NULL, 0 },
/* FLD 24 */ { 0 , " NO USE " , 3 , 0 , 0 , 0 , NULL, 0 },
/* FLD 25 */ { 0 , " POINT OF SERVICE CONDITION CODE " , 2 , 0 , 0 , 0 , NULL, 0 },
/* FLD 26 */ { 0 , " NO USE " , 2 , 0 , 0 , 0 , NULL, 0 },
/* FLD 27 */ { 0 , " NO USE " , 1 , 0 , 0 , 0 , NULL, 0 },
/* FLD 28 */ { 0 , " field27 " , 6 , 0 , 0 , 0 , NULL, 0 },
/* FLD 29 */ { 0 , " NO USE " , 8 , 0 , 1 , 0 , NULL, 0 },
/* FLD 30 */ { 0 , " NO USE " , 8 , 0 , 1 , 0 , NULL, 0 },
/* FLD 31 */ { 0 , " NO USE " , 8 , 0 , 1 , 0 , NULL, 0 },
/* FLD 32 */ { 0 , " ACQUIRER INSTITUTION ID. CODE " , 11 , 0 , 2 , 0 , NULL, 0 },
/* FLD 33 */ { 0 , " FORWARDING INSTITUTION ID. CODE " , 11 , 0 , 2 , 0 , NULL, 0 },
/* FLD 34 */ { 0 , " NO USE " , 28 , 0 , 2 , 0 , NULL, 0 },
/* FLD 35 */ { 0 , " TRACK 2 DATA " , 37 , 0 , 2 , 0 , NULL, 0 },
/* FLD 36 */ { 0 , " TRACK 3 DATA " , 104 , 0 , 3 , 0 , NULL, 0 },
/* FLD 37 */ { 0 , " RETRIEVAL REFERENCE NUMBER " , 12 , 0 , 0 , 0 , NULL, 0 },
/* FLD 38 */ { 0 , " AUTH. IDENTIFICATION RESPONSE " , 6 , 0 , 0 , 0 , NULL, 0 },
/* FLD 39 */ { 0 , " RESPONSE CODE " , 2 , 0 , 0 , 0 , NULL, 0 },
/* FLD 40 */ { 0 , " NO USE " , 3 , 0 , 0 , 0 , NULL, 0 },
/* FLD 41 */ { 0 , " CARD ACCEPTOR TERMINAL ID. " , 8 , 0 , 0 , 0 , NULL, 0 },
/* FLD 42 */ { 0 , " CARD ACCEPTOR IDENTIFICATION CODE " , 15 , 0 , 0 , 0 , NULL, 0 },
/* FLD 43 */ { 0 , " CARD ACCEPTOR NAME LOCATION " , 40 , 0 , 0 , 0 , NULL, 0 },
/* FLD 44 */ { 0 , " ADDITIONAL RESPONSE DATA " , 25 , 0 , 2 , 0 , NULL, 0 },
/* FLD 45 */ { 0 , " NO USE " , 76 , 0 , 2 , 0 , NULL, 0 },
/* FLD 46 */ { 0 , " NO USE " , 999 , 0 , 3 , 0 , NULL, 0 },
/* FLD 47 */ { 0 , " field47 " , 999 , 0 , 3 , 0 , NULL, 0 },
/* FLD 48 */ { 0 , " ADDITIONAL DATA --- PRIVATE " , 999 , 0 , 3 , 0 , NULL, 0 },
/* FLD 49 */ { 0 , " CURRENCY CODE,TRANSACTION " , 3 , 0 , 0 , 0 , NULL, 0 },
/* FLD 50 */ { 0 , " CURRENCY CODE,SETTLEMENT " , 3 , 0 , 0 , 0 , NULL, 0 },
/* FLD 51 */ { 0 , " NO USE " , 3 , 0 , 0 , 0 , NULL, 0 },
/* FLD 52 */ { 0 , " PERSONAL IDENTIFICATION NUMBER DATA " , 8 , 0 , 0 , 2 , NULL, 0 },
/* FLD 53 */ { 0 , " SECURITY RELATED CONTROL INformATION " , 16 , 0 , 0 , 0 , NULL, 0 },
/* FLD 54 */ { 0 , " ADDITIONAL AMOUNTS " , 120 , 0 , 3 , 0 , NULL, 0 },
/* FLD 55 */ { 0 , " NO USE " , 999 , 0 , 3 , 0 , NULL, 0 },
/* FLD 56 */ { 0 , " NO USE " , 999 , 0 , 3 , 0 , NULL, 0 },
/* FLD 57 */ { 0 , " NO USE " , 999 , 0 , 3 , 0 , NULL, 0 },
/* FLD 58 */ { 0 , " NO USE " , 999 , 0 , 3 , 0 , NULL, 0 },
/* FLD 59 */ { 0 , " NO USE " , 999 , 0 , 3 , 0 , NULL, 0 },
/* FLD 60 */ { 0 , " NO USE " , 999 , 0 , 3 , 0 , NULL, 0 },
/* FLD 61 */ { 0 , " NO USE " , 999 , 0 , 3 , 0 , NULL, 0 },
/* FLD 62 */ { 0 , " NO USE " , 999 , 0 , 3 , 0 , NULL, 0 },
/* FLD 63 */ { 0 , " NO USE " , 999 , 0 , 3 , 0 , NULL, 0 },
/* FLD 64 */ { 0 , " MESSAGE AUTHENTICATION CODE FIELD " , 8 , 0 , 0 , 2 , NULL, 0 },
/* FLD 65 */ { 0 , " NO USE " , 999 , 0 , 3 , 0 , NULL, 0 },
/* FLD 66 */ { 0 , " NO USE " , 1 , 0 , 0 , 0 , NULL, 0 },
/* FLD 67 */ { 0 , " NO USE " , 999 , 0 , 3 , 0 , NULL, 0 },
/* FLD 68 */ { 0 , " NO USE " , 999 , 0 , 3 , 0 , NULL, 0 },
/* FLD 69 */ { 0 , " NO USE " , 999 , 0 , 3 , 0 , NULL, 0 },
/* FLD 70 */ { 0 , " SYSTEM MANAGEMENT INformATION CODE " , 3 , 0 , 0 , 0 , NULL, 0 },
/* FLD 71 */ { 0 , " NO USE " , 999 , 0 , 3 , 0 , NULL, 0 },
/* FLD 72 */ { 0 , " NO USE " , 999 , 0 , 3 , 0 , NULL, 0 },
/* FLD 73 */ { 0 , " NO USE " , 6 , 0 , 0 , 0 , NULL, 0 },
/* FLD 74 */ { 0 , " NUMBER OF CREDITS " , 10 , 0 , 0 , 0 , NULL, 0 },
/* FLD 75 */ { 0 , " REVERSAL NUMBER OF CREDITS " , 10 , 0 , 0 , 0 , NULL, 0 },
/* FLD 76 */ { 0 , " NUMBER OF DEBITS " , 10 , 0 , 0 , 0 , NULL, 0 },
/* FLD 77 */ { 0 , " REVERSAL NUMBER OF DEBITS " , 10 , 0 , 0 , 0 , NULL, 0 },
/* FLD 78 */ { 0 , " NUMBER OF TRANSFER " , 10 , 0 , 0 , 0 , NULL, 0 },
/* FLD 79 */ { 0 , " REVERSAL NUMBER OF TRANSFER " , 10 , 0 , 0 , 0 , NULL, 0 },
/* FLD 80 */ { 0 , " NUMBER OF INQUIRS " , 10 , 0 , 0 , 0 , NULL, 0 },
/* FLD 81 */ { 0 , " AUTHORIZATION NUMBER " , 10 , 0 , 0 , 0 , NULL, 0 },
/* FLD 82 */ { 0 , " NO USE " , 12 , 0 , 0 , 0 , NULL, 0 },
/* FLD 83 */ { 0 , " CREDITS,TRANSCATION FEEAMOUNT " , 12 , 0 , 0 , 0 , NULL, 0 },
/* FLD 84 */ { 0 , " NO USE " , 12 , 0 , 0 , 0 , NULL, 0 },
/* FLD 85 */ { 0 , " DEBITS,TRANSCATION FEEAMOUNT " , 12 , 0 , 0 , 0 , NULL, 0 },
/* FLD 86 */ { 0 , " AMOUNT OF CREDITS " , 16 , 0 , 0 , 0 , NULL, 0 },
/* FLD 87 */ { 0 , " REVERSAL AMOUNT OF CREDITS " , 16 , 0 , 0 , 0 , NULL, 0 },
/* FLD 88 */ { 0 , " AMOUNT OF DEBITS " , 16 , 0 , 0 , 0 , NULL, 0 },
/* FLD 89 */ { 0 , " REVERSAL AMOUNT OF DEBITS " , 16 , 0 , 0 , 0 , NULL, 0 },
/* FLD 90 */ { 0 , " ORIGINAL DATA ELEMENTS " , 42 , 0 , 0 , 0 , NULL, 0 },
/* FLD 91 */ { 0 , " FILE UPDATE CODE " , 1 , 0 , 0 , 0 , NULL, 0 },
/* FLD 92 */ { 0 , " NO USE " , 999 , 0 , 3 , 0 , NULL, 0 },
/* FLD 93 */ { 0 , " NO USE " , 999 , 0 , 3 , 0 , NULL, 0 },
/* FLD 94 */ { 0 , " SERVICE INDICATOR " , 7 , 0 , 0 , 0 , NULL, 0 },
/* FLD 95 */ { 0 , " REPLACEMENT AMOUNTS " , 42 , 0 , 0 , 0 , NULL, 0 },
/* FLD 96 */ { 0 , " NO USE " , 8 , 0 , 0 , 0 , NULL, 0 },
/* FLD 97 */ { 0 , " AMOUNT OF NET SETTLEMENT " , 16 , 0 , 0 , 0 , NULL, 0 },
/* FLD 98 */ { 0 , " NO USE " , 999 , 0 , 3 , 0 , NULL, 0 },
/* FLD 99 */ { 0 , " SETTLEMENT INSTITUTION ID " , 11 , 0 , 2 , 0 , NULL, 0 },
/* FLD 100 */ { 0 , " RECVEING INSTITUTION ID " , 11 , 0 , 2 , 0 , NULL, 0 },
/* FLD 101 */ { 0 , " FILENAME " , 17 , 0 , 2 , 0 , NULL, 0 },
/* FLD 102 */ { 0 , " ACCOUNT IDENTIFICATION1 " , 28 , 0 , 2 , 0 , NULL, 0 },
/* FLD 103 */ { 0 , " ACCOUNT IDENTIFICATION2 " , 28 , 0 , 2 , 0 , NULL, 0 },
/* FLD 104 */ { 0 , " NO USE " , 999 , 0 , 3 , 0 , NULL, 0 },
/* FLD 105 */ { 0 , " NO USE " , 999 , 0 , 3 , 0 , NULL, 0 },
/* FLD 106 */ { 0 , " NO USE " , 999 , 0 , 3 , 0 , NULL, 0 },
/* FLD 107 */ { 0 , " NO USE " , 999 , 0 , 3 , 0 , NULL, 0 },
/* FLD 108 */ { 0 , " NO USE " , 999 , 0 , 3 , 0 , NULL, 0 },
/* FLD 109 */ { 0 , " NO USE " , 999 , 0 , 3 , 0 , NULL, 0 },
/* FLD 110 */ { 0 , " NO USE " , 999 , 0 , 3 , 0 , NULL, 0 },
/* FLD 111 */ { 0 , " NO USE " , 999 , 0 , 3 , 0 , NULL, 0 },
/* FLD 112 */ { 0 , " NO USE " , 999 , 0 , 3 , 0 , NULL, 0 },
/* FLD 113 */ { 0 , " NO USE " , 999 , 0 , 3 , 0 , NULL, 0 },
/* FLD 114 */ { 0 , " NO USE " , 999 , 0 , 3 , 0 , NULL, 0 },
/* FLD 115 */ { 0 , " NO USE " , 999 , 0 , 3 , 0 , NULL, 0 },
/* FLD 116 */ { 0 , " NO USE " , 999 , 0 , 3 , 0 , NULL, 0 },
/* FLD 117 */ { 0 , " NO USE " , 999 , 0 , 3 , 0 , NULL, 0 },
/* FLD 118 */ { 0 , " NO USE " , 999 , 0 , 3 , 0 , NULL, 0 },
/* FLD 119 */ { 0 , " NO USE " , 999 , 0 , 3 , 0 , NULL, 0 },
/* FLD 120 */ { 0 , " NO USE " , 999 , 0 , 3 , 0 , NULL, 0 },
/* FLD 121 */ { 0 , " NO USE " , 999 , 0 , 3 , 0 , NULL, 0 },
/* FLD 122 */ { 0 , " NO USE " , 999 , 0 , 3 , 0 , NULL, 0 },
/* FLD 123 */ { 0 , " NEW PIN DATA " , 8 , 0 , 3 , 2 , NULL, 0 },
/* FLD 124 */ { 0 , " NO USE " , 999 , 0 , 3 , 0 , NULL, 0 },
/* FLD 125 */ { 0 , " NO USE " , 999 , 0 , 3 , 0 , NULL, 0 },
/* FLD 126 */ { 0 , " NO USE " , 999 , 0 , 3 , 0 , NULL, 0 },
/* FLD 127 */ { 0 , " NO USE " , 999 , 0 , 3 , 0 , NULL, 0 },
/* FLD 128 */ { 0 , " MESSAGE AUTHENTICATION CODE FIELD " , 8 , 0 , 0 , 2 , NULL, 0 },
};
/* Set bit in specified position */
void CISO8583::setBit(BYTE * pBytes, int nPos)
{
if (nPos % 8 == 0 )
pBytes[nPos / 8 - 1 ] |= 0x01 ;
else
pBytes[(unsigned int )floor(nPos / 8 )] |= ( 0x80 >> (nPos % 8 - 1 ));
if (nPos > 64 )
setBit(pBytes, 1 );
}
/* Test to see if bit position of p is set */
bool CISO8583::testBit( const BYTE * pBytes, int nPos)
{
unsigned int nOffset;
BYTE nMask;
nOffset = nPos % 8 == 0 ? nPos / 8 - 1 : (unsigned int )floor(nPos / 8 );
nMask = nPos % 8 == 0 ? 0x01 : ( 0x80 >> (nPos % 8 - 1 ));
return (pBytes[nOffset] & nMask) == nMask;
}
/* Write message in xml format */
bool CISO8583::writeXML(LPCTSTR pszXMLFile)
{
int i = 0 ;
BYTE bitmap[ 16 ];
char sBitMap[ 33 ] = { ' \0 ' };
TCHAR * szFieldType[ 3 ] = { " string " , " int " , " binary " };
FILE * fp = fopen(pszXMLFile, " w " );
if (NULL == fp)
return false ;
/* write bitmap */
memset(bitmap, 0 , sizeof (bitmap));
map < int , ISO8583FieldData > ::iterator it = m_fields.begin();
while (it != m_fields.end()) {
setBit(bitmap, it -> first);
it ++ ;
}
for (i = 0 ; i < 16 ; i ++ )
_snprintf(sBitMap + 2 * i, 2 , " %02x " , bitmap[i]);
fprintf(fp, " <?xml version=\ " 1.0 \ " encoding=\ " GB2312\ " ?>\r\n " );
fprintf(fp, " <ISO8583 fieldscount=\ " % d\ " totalbytes=\ " % d\ " bitmap=\ " % s\ " > " , m_fields.size(), this -> GetMessageLength(), sBitMap);
/* write fields */
it = m_fields.begin();
while (it != m_fields.end()) {
fprintf(fp, " \r\n\t<Field no=\ " % d\ " type=\ " % s\ " fieldlength=\ " % d\ " datalength=\ " % d\ " >\n " , it -> first, szFieldType[Tbl8583[it -> first - 1 ].datatype], Tbl8583[it -> first - 1 ].length, it -> second.len);
if (Tbl8583[it -> first - 1 ].datatype == 1 )
fprintf(fp, " \t\t%s " , ( char * )it -> second.data);
else {
fprintf(fp, " \t\t " );
for (i = 0 ; i < it -> second.len; i ++ )
fprintf(fp, " %02X " , (BYTE)it -> second.data[i]);
}
fprintf(fp, " \n\t</Field> " );
it ++ ;
}
fprintf(fp, " \n</ISO8583> " );
fclose(fp);
return true ;
}
bool CISO8583::writeBIN(LPCTSTR pszBINFile)
{
int i = 0 ;
BYTE bitmap[ 16 ];
FILE * fp = fopen(pszBINFile, " wb " );
if (NULL == fp)
return false ;
/* write bitmap */
memset(bitmap, 0 , sizeof (bitmap));
map < int , ISO8583FieldData > ::iterator it = m_fields.begin();
while (it != m_fields.end()) {
setBit(bitmap, it -> first);
it ++ ;
}
fwrite(bitmap, 1 , sizeof (bitmap), fp);
/* write fields */
it = m_fields.begin();
while (it != m_fields.end()) {
if (Tbl8583[it -> first - 1 ].variable_flag == 0 )
fwrite(it -> second.data, 1 , it -> second.len, fp);
else if (Tbl8583[it -> first - 1 ].variable_flag == 2 ) {
fprintf(fp, " %02d " , it -> second.len);
fwrite(it -> second.data, 1 , it -> second.len, fp);
}
else if (Tbl8583[it -> first - 1 ].variable_flag == 3 ) {
fprintf(fp, " %03d " , it -> second.len);
fwrite(it -> second.data, 1 , it -> second.len, fp);
}
it ++ ;
}
fclose(fp);
return true ;
}
bool CISO8583::writeHEX(LPCTSTR pszHEXFile)
{
int i = 0 , j = 0 , round = 0 , length = this -> GetMessageLength();
FILE * fp = fopen(pszHEXFile, " wb " );
if (NULL == fp)
return false ;
BYTE * pBytes = new BYTE[length];
BYTE * p = pBytes;
if (NULL == pBytes)
return false ;
memset(pBytes, 0 , length);
/* write bitmap */
map < int , ISO8583FieldData > ::iterator it = m_fields.begin();
while (it != m_fields.end()) {
setBit(pBytes, it -> first);
it ++ ;
}
p += 16 ;
/* write fields */
it = m_fields.begin();
while (it != m_fields.end()) {
if (Tbl8583[it -> first - 1 ].variable_flag == 0 ) {
memcpy(p, it -> second.data, it -> second.len);
}
else if (Tbl8583[it -> first - 1 ].variable_flag == 2 ) {
_snprintf(( char * )p, 2 , " %02d " , it -> second.len);
p += 2 ;
memcpy(p, it -> second.data, it -> second.len);
}
else if (Tbl8583[it -> first - 1 ].variable_flag == 3 ) {
_snprintf(( char * )p, 3 , " %03d " , it -> second.len);
p += 3 ;
memcpy(p, it -> second.data, it -> second.len);
}
p += it -> second.len;
it ++ ;
}
/* write to file in ultraedit hex-view format */
for (i = 0 ; i < length; i ++ ) {
if (i == 0 )
fprintf(fp, " %08Xh: " , round);
fprintf(fp, " %02X " , pBytes[i]);
if ( ++ round % 16 == 0 && i != length - 1 ) {
fwrite( " ; " , 1 , 3 , fp);
p = pBytes + i - 15 ;
for (j = 0 ; j < 16 ; j ++ )
fprintf(fp, " %c " , (p[j] == 0 || p[j] == ' \r ' || p[j] == ' \n ' ) ? ' . ' : p[j]);
fprintf(fp, " \r\n%08Xh: " , round);
}
}
if ((round = length % 16 ) != 0 ) {
for (i = 0 ; i < 16 - round; i ++ )
fwrite( " " , 1 , 3 , fp);
fwrite( " ; " , 1 , 3 , fp);
p = pBytes + length - round;
for (i = 0 ; i < round; i ++ )
fprintf(fp, " %c " , (p[i] == 0 || p[i] == ' \r ' || p[i] == ' \n ' ) ? ' . ' : p[i]);
}
delete pBytes;
fclose(fp);
return true ;
}
bool CISO8583::WriteToFile(LPCTSTR pszFile, FileType type)
{
if (type == CISO8583::XML)
return writeXML(pszFile);
else if (type == CISO8583::BIN)
return writeBIN(pszFile);
else if (type == CISO8583::HEX)
return writeHEX(pszFile);
return false ;
}
/* Get message length in bytes */
int CISO8583::GetMessageLength()
{
int len = 0 ;
map < int , ISO8583FieldData > ::iterator it = m_fields.begin();
while (it != m_fields.end()) {
len = len + it -> second.len + Tbl8583[it -> first - 1 ].variable_flag;
it ++ ;
}
return len + 16 ;
}
CISO8583Writer::CISO8583Writer()
{
}
CISO8583Writer:: ~ CISO8583Writer()
{
map < int , ISO8583FieldData > ::iterator it = m_fields.begin();
while (it != m_fields.end()) {
delete it -> second.data;
it ++ ;
}
}
/* Copy message out */
int CISO8583Writer::CopyOut(BYTE * pOutBuf, int nBufLen)
{
int offset = 16 ;
if (NULL == pOutBuf || nBufLen < GetMessageLength())
return - 1 ;
/* clear bitmap */
memset(( void * )pOutBuf, 0 , 16 );
map < int , ISO8583FieldData > ::iterator it = m_fields.begin();
while (it != m_fields.end()) {
/* set bitmap */
setBit(pOutBuf, it -> first);
/* copy data */
if (Tbl8583[it -> first - 1 ].variable_flag == 0 ) {
memcpy(pOutBuf + offset, it -> second.data, it -> second.len);
offset += it -> second.len;
}
else if (Tbl8583[it -> first - 1 ].variable_flag == 2 ) {
_snprintf(( char * )(pOutBuf + offset), 2 , " %02d " , it -> second.len);
memcpy(pOutBuf + offset + 2 , it -> second.data, it -> second.len);
offset = offset + it -> second.len + 2 ;
}
else if (Tbl8583[it -> first - 1 ].variable_flag == 3 ) {
_snprintf(( char * )(pOutBuf + offset), 3 , " %03d " , it -> second.len);
memcpy(pOutBuf + offset + 3 , it -> second.data, it -> second.len);
offset = offset + it -> second.len + 3 ;
}
it ++ ;
}
return offset;
}
/* write specified field, if pFieldBuf is NULL then this field will be cleared */
const BYTE * CISO8583Writer::WriteField( int nField, int nFieldLen, BYTE * pFieldBuf)
{
if (nField > 128 || nField < 1 )
throw " field should between 1 and 128 " ;
map < int , ISO8583FieldData > ::iterator it = m_fields.find(nField);
/* delete the specified field if it exists */
if (it != m_fields.end()) {
delete it -> second.data;
m_fields.erase(it);
}
/* clear the specified field and return if pFieldBuf is NULL */
if (NULL == pFieldBuf)
return NULL;
/* copy data */
ISO8583FieldData field;
field.len = nFieldLen;
field.data = new BYTE[field.len];
if (NULL == field.data)
return NULL;
memcpy(field.data, pFieldBuf, field.len);
/* add field */
m_fields[nField] = field;
return field.data;
}
CISO8583Reader::CISO8583Reader()
{
}
CISO8583Reader:: ~ CISO8583Reader()
{
m_fields.clear();
}
bool CISO8583Reader::ReadMessage( const BYTE * pMessage)
{
try {
return parseFields(pMessage);
}
catch () {
return false ;
}
}
/* Get position and length for each field */
bool CISO8583Reader::parseFields( const BYTE * pMessage)
{
bool extensionMode = testBit(pMessage, 1 );
DWORD dwOffset = 16 ;
BYTE len[ 4 ];
/* Test bit pos 2 - 128 or 2 - 64 */
for ( int i = 2 ; i <= 128 && extensionMode; i ++ ) {
if ( ! testBit(pMessage, i)) continue ;
/* find data position and length for each field */
ISO8583FieldData field;
if (Tbl8583[i - 1 ].variable_flag == 0 ) {
field.len = Tbl8583[i - 1 ].length;
field.data = (BYTE * )pMessage + dwOffset;
dwOffset += field.len;
}
else {
memset(len, 0 , sizeof (len));
memcpy(( void * )len, ( void * )(pMessage + dwOffset), Tbl8583[i - 1 ].variable_flag);
field.len = atol(( char * )len);
field.data = (BYTE * )(pMessage + dwOffset + Tbl8583[i - 1 ].variable_flag);
dwOffset = dwOffset + field.len + Tbl8583[i - 1 ].variable_flag;
}
m_fields[i] = field;
}
return true ;
}
/* Get fields number that is set in the bitmap, count should large than value return by FieldsCount() */
int CISO8583Reader::GetFields( int * fields, int count)
{
int fcount = m_fields.size() > count ? count : m_fields.size();
map < int , ISO8583FieldData > ::iterator it = m_fields.begin();
for ( int i = 0 ; i < fcount; i ++ ) {
fields[i] = it -> first;
it ++ ;
}
return fcount;
}
/* Get fields count */
int CISO8583Reader::FieldsCount()
{
return m_fields.size();
}
/* Find to see whether the specified field exist */
bool CISO8583Reader::FieldExist( int nField)
{
return m_fields.find(nField) != m_fields.end();
}
/* Find to see whether all fields in pFields array exist */
int CISO8583Reader::FieldsExist( int * fields, int nCount)
{
for ( int i = 0 ; i < nCount; i ++ ) {
if ( ! FieldExist(fields[i]))
return fields[i];
}
return 0 ;
}
/* Get field length exclusive the LLLVAR or LLVAR part */
int CISO8583Reader::FieldLength( int nField)
{
if (nField > 128 ) return - 1 ;
map < int , ISO8583FieldData > ::iterator it = m_fields.find(nField);
if (it == m_fields.end())
return - 1 ;
/* substract the LLL or LL length */
return it -> second.len - Tbl8583[nField - 1 ].variable_flag;
}
/* Get Field's data, not include the LL or LLL length value if it is varlength field */
int CISO8583Reader::ReadField( int nField, BYTE * pOutBuf, int nBufLen)
{
map < int , ISO8583FieldData > ::iterator it = m_fields.find(nField);
if (it == m_fields.end())
return - 1 ;
int nFieldLen = it -> second.len; // - Tbl8583[nField - 1].variable_flag;
if (nBufLen < it -> second.len)
return - 1 ;
memcpy(pOutBuf, it -> second.data, nFieldLen);
return nFieldLen;
}