using System.Collections.Generic;
public static void Main()
public class GatewayCardEMVData
private readonly int m_length;
private readonly int m_valueOffset;
private GatewayCardEMVData( int tag, int length, int valueOffset, byte[] rawData )
m_valueOffset = valueOffset;
public int Tag { get; private set; }
public byte[] RawData { get; private set; }
public ICollection<GatewayCardEMVData> SubData { get; private set; } = new List<GatewayCardEMVData>();
byte[] result = new byte[m_length];
Array.Copy( RawData, m_valueOffset, result, 0, m_length );
get { return Tag.ToString( "X" ); }
get { return GetHexString( Value ); }
public static ICollection<GatewayCardEMVData> ParseTLV( string hexTlv )
if( string.IsNullOrWhiteSpace( hexTlv ) )
throw new ArgumentException( nameof( hexTlv ) );
return ParseTLV( GetBytes( hexTlv ) );
public static ICollection<GatewayCardEMVData> ParseTLV( byte[] rawTlv )
if( rawTlv == null || rawTlv.Length == 0 )
throw new ArgumentException( nameof( rawTlv ) );
var result = new List<GatewayCardEMVData>();
ParseTlv( rawTlv, result );
private static void ParseTlv( byte[] rawTlv, ICollection<GatewayCardEMVData> result )
for( int i = 0, start = 0; i < rawTlv.Length; start = i )
bool constructedTlv = ( rawTlv[i] & 0x20 ) != 0;
bool moreBytes = ( rawTlv[i] & 0x1F ) == 0x1F;
while( moreBytes && ( rawTlv[++i] & 0x80 ) != 0 ) ;
int tag = GetInt( rawTlv, start, i - start );
bool multiByteLength = ( rawTlv[i] & 0x80 ) != 0;
int length = multiByteLength ? GetInt( rawTlv, i + 1, rawTlv[i] & 0x1F ) : rawTlv[i];
i = multiByteLength ? i + ( rawTlv[i] & 0x1F ) + 1 : i + 1;
byte[] rawData = new byte[i - start];
Array.Copy( rawTlv, start, rawData, 0, i - start );
var tlv = new GatewayCardEMVData( tag, length, rawData.Length - length, rawData );
ParseTlv( tlv.Value, tlv.SubData );
private static string GetHexString( byte[] arr )
var sb = new StringBuilder( arr.Length * 2 );
sb.AppendFormat( "{0:X2}", b );
private static byte[] GetBytes( string hexString )
return Enumerable.Range( 0, hexString.Length )
.Where( x => x % 2 == 0 )
.Select( x => Convert.ToByte( hexString.Substring( x, 2 ), 16 ) )
private static int GetInt( byte[] data, int offset, int length )
for( var i = 0; i < length; i++ )
result = ( result << 8 ) | data[offset + i];