Skip to content

Commit

Permalink
Merge pull request jpos#58 from vishnupillai/master
Browse files Browse the repository at this point in the history
Fix some issues with EMV - c and cn data types
Handle keepAlive message on BaseChannel
  • Loading branch information
ar committed May 23, 2014
2 parents e9b59ae + af9c36a commit 4aacb1a
Show file tree
Hide file tree
Showing 6 changed files with 137 additions and 92 deletions.
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ allprojects {
[ compileJava, compileTestJava, javadoc ]*.options*.encoding = 'UTF-8'
def isSnapshot = version.contains("SNAPSHOT")
def mavenCentralRepo = isSnapshot ?
'https://oss.sonatype.org/content/repositories/snapshots/' :
'https://oss.sonatype.org/content/repositories/snapshots/' :
'https://oss.sonatype.org/service/local/staging/deploy/maven2';

sourceCompatibility = 1.6
Expand Down
86 changes: 43 additions & 43 deletions jpos/src/main/java/org/jpos/emv/EMVStandardTagType.java

Large diffs are not rendered by default.

9 changes: 9 additions & 0 deletions jpos/src/main/java/org/jpos/iso/BaseChannel.java
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ public abstract class BaseChannel extends Observable
private int port, timeout, connectTimeout, localPort;
private int maxPacketLength = 100000;
private boolean keepAlive;
private boolean expectKeepAlive;
private boolean soLingerOn = true;
private int soLingerSeconds = 5;
private Configuration cfg;
Expand Down Expand Up @@ -696,6 +697,13 @@ public ISOMsg receive() throws IOException, ISOException {

synchronized (serverInLock) {
int len = getMessageLength();
if (expectKeepAlive) {
while (len == 0) {
//If zero length, this is a keep alive msg
Logger.log(new LogEvent(this, "receive", "Zero length keep alive message received"));
len = getMessageLength();
}
}
int hLen = getHeaderLength();

if (len == -1) {
Expand Down Expand Up @@ -996,6 +1004,7 @@ public void setConfiguration (Configuration cfg)
}
setOverrideHeader(cfg.getBoolean ("override-header", false));
keepAlive = cfg.getBoolean ("keep-alive", false);
expectKeepAlive = cfg.getBoolean ("expect-keep-alive", false);
if (socketFactory != this && socketFactory instanceof Configurable)
((Configurable)socketFactory).setConfiguration (cfg);
try {
Expand Down
20 changes: 10 additions & 10 deletions jpos/src/main/java/org/jpos/tlv/TLVDataFormat.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,16 +23,16 @@
* @author Vishnu Pillai
*/
public enum TLVDataFormat {
CONSTRUCTED,
ASCII_NUMERIC,
ASCII_ALPHA,
ASCII_ALPHA_NUMERIC,
ASCII_ALPHA_NUMERIC_SPACE,
ASCII_ALPHA_NUMERIC_SPECIAL,
BINARY,
COMPRESSED_NUMERIC,
NUMERIC,
DATE_YYMMDD,
ALPHA,
ALPHA_NUMERIC,
ALPHA_NUMERIC_SPACE,
ALPHA_NUMERIC_SPECIAL,
CARD_NUMBER,
TIME_HHMMSS,
PROPRIETARY
CONSTRUCTED,
PACKED_NUMERIC,
PACKED_NUMERIC_DATE_YYMMDD,
PACKED_NUMERIC_TIME_HHMMSS,
PROPRIETARY;
}
89 changes: 59 additions & 30 deletions jpos/src/main/java/org/jpos/tlv/packager/bertlv/BERTLVPackager.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
import org.jpos.iso.ISOFieldPackager;
import org.jpos.iso.ISOMsg;
import org.jpos.iso.ISOUtil;
import org.jpos.iso.Interpreter;
import org.jpos.iso.LiteralInterpreter;
import org.jpos.iso.packager.GenericPackager;
import org.jpos.tlv.ISOTaggedField;
Expand Down Expand Up @@ -59,7 +60,8 @@ public abstract class BERTLVPackager extends GenericPackager {

private static final LiteralInterpreter literalInterpreter = LiteralInterpreter.INSTANCE;
private static final AsciiInterpreter asciiInterpreter = AsciiInterpreter.INSTANCE;
private static final BCDInterpreter bcdInterpreter = BCDInterpreter.LEFT_PADDED;
private static final BCDInterpreter bcdInterpreterLeftPaddedZero = BCDInterpreter.LEFT_PADDED;
private static final BCDInterpreter bcdInterpreterRightPaddedF = BCDInterpreter.RIGHT_PADDED_F;

private final BinaryInterpreter tagInterpreter;
private final BinaryInterpreter lengthInterpreter;
Expand Down Expand Up @@ -166,7 +168,6 @@ private byte[] packTLV(ISOTaggedField c) throws ISOException {
throw new ISOException(e);
}


byte[] valueBytes = new byte[valueInterpreter.getPackedLength(rawValueBytes.length)];
valueInterpreter.interpret(rawValueBytes, valueBytes, 0);

Expand Down Expand Up @@ -264,12 +265,11 @@ public int unpack(ISOComponent m, byte[] b, boolean nested) throws ISOException
System.arraycopy(b, consumed, value, 0, value.length);
}

int lengthAdjusted = length + length % 2;
int uninterpretLength = length * (lengthAdjusted / valueInterpreter.getPackedLength(lengthAdjusted));
int uninterpretLength = getUninterpretLength(length, valueInterpreter);
byte[] rawValueBytes =
valueInterpreter.uninterpret(value, 0, uninterpretLength);

tlvSubFieldData = unpackValue(tag, rawValueBytes, subFieldNumber);
tlvSubFieldData = unpackValue(tag, rawValueBytes, subFieldNumber, length);


consumed = consumed + length;
Expand Down Expand Up @@ -355,17 +355,20 @@ protected byte[] packValue(String tagNameHex, final ISOComponent c) throws ISOEx
tagValue = (String) c.getValue();
switch (dataFormat) {
case COMPRESSED_NUMERIC:
case CARD_NUMBER:
case DATE_YYMMDD:
case TIME_HHMMSS:
packedValue = new byte[bcdInterpreter.getPackedLength(tagValue.length())];
bcdInterpreter.interpret(tagValue, packedValue, 0);
packedValue = new byte[bcdInterpreterRightPaddedF.getPackedLength(tagValue.length())];
bcdInterpreterRightPaddedF.interpret(tagValue, packedValue, 0);
break;
case PACKED_NUMERIC:
case PACKED_NUMERIC_DATE_YYMMDD:
case PACKED_NUMERIC_TIME_HHMMSS:
packedValue = new byte[bcdInterpreterLeftPaddedZero.getPackedLength(tagValue.length())];
bcdInterpreterLeftPaddedZero.interpret(tagValue, packedValue, 0);
break;
case NUMERIC:
case ALPHA:
case ALPHA_NUMERIC:
case ALPHA_NUMERIC_SPACE:
case ALPHA_NUMERIC_SPECIAL:
case ASCII_NUMERIC:
case ASCII_ALPHA:
case ASCII_ALPHA_NUMERIC:
case ASCII_ALPHA_NUMERIC_SPACE:
case ASCII_ALPHA_NUMERIC_SPECIAL:
packedValue = new byte[asciiInterpreter.getPackedLength(tagValue.length())];
asciiInterpreter.interpret(tagValue, packedValue, 0);
break;
Expand Down Expand Up @@ -396,29 +399,43 @@ protected byte[] packValue(String tagNameHex, final ISOComponent c) throws ISOEx
}

private ISOComponent unpackValue(String tagNameHex, final byte[] tlvData,
int subFieldNumber) throws ISOException, UnknownTagNumberException {
int subFieldNumber, int dataLength) throws ISOException, UnknownTagNumberException {
final int tagNumber = Integer.parseInt(tagNameHex, 16);
final TLVDataFormat dataFormat = getTagFormatMapper().getFormat(tagNumber);
ISOComponent value;
String unpackedValue;
int length;
int uninterpretLength;
switch (dataFormat) {
case COMPRESSED_NUMERIC:
case CARD_NUMBER:
case DATE_YYMMDD:
case TIME_HHMMSS:
int lengthAdjusted = tlvData.length + tlvData.length % 2;
length = tlvData.length * (lengthAdjusted / bcdInterpreter.getPackedLength(lengthAdjusted));
unpackedValue = bcdInterpreter.uninterpret(tlvData, 0, length);
uninterpretLength = getUninterpretLength(dataLength, bcdInterpreterRightPaddedF);
unpackedValue = bcdInterpreterRightPaddedF.uninterpret(tlvData, 0, uninterpretLength);
if (unpackedValue.length() > 1) {
if (unpackedValue.charAt(unpackedValue.length() - 1) == 'F') {
unpackedValue = unpackedValue.substring(0, unpackedValue.length() - 1);
}
}
value = new ISOField(subFieldNumber, unpackedValue);
break;
case PACKED_NUMERIC:
case PACKED_NUMERIC_DATE_YYMMDD:
case PACKED_NUMERIC_TIME_HHMMSS:
uninterpretLength = getUninterpretLength(dataLength, bcdInterpreterLeftPaddedZero);
unpackedValue = bcdInterpreterLeftPaddedZero.uninterpret(tlvData, 0, uninterpretLength);

if (unpackedValue.length() > 1) {
if (unpackedValue.charAt(0) == '0') {
unpackedValue = unpackedValue.substring(1);
}
}
value = new ISOField(subFieldNumber, unpackedValue);
break;
case NUMERIC:
case ALPHA:
case ALPHA_NUMERIC:
case ALPHA_NUMERIC_SPACE:
case ALPHA_NUMERIC_SPECIAL:
length = tlvData.length;
unpackedValue = asciiInterpreter.uninterpret(tlvData, 0, length);
case ASCII_NUMERIC:
case ASCII_ALPHA:
case ASCII_ALPHA_NUMERIC:
case ASCII_ALPHA_NUMERIC_SPACE:
case ASCII_ALPHA_NUMERIC_SPECIAL:
uninterpretLength = getUninterpretLength(dataLength, asciiInterpreter);
unpackedValue = asciiInterpreter.uninterpret(tlvData, 0, uninterpretLength);
value = new ISOField(subFieldNumber, unpackedValue);
break;
case BINARY:
Expand All @@ -441,6 +458,18 @@ public void unpack(ISOComponent m, InputStream in) throws IOException, ISOExcept
"Call to unpack(ISOComponent m, InputStream in) was not expected.");
}

private int getUninterpretLength(int length, BinaryInterpreter interpreter) {
int lengthAdjusted = length + length % 2;
int uninterpretLength = length * (lengthAdjusted / interpreter.getPackedLength(lengthAdjusted));
return uninterpretLength;
}

private int getUninterpretLength(int length, Interpreter interpreter) {
int lengthAdjusted = length + length % 2;
int uninterpretLength = length * (lengthAdjusted / interpreter.getPackedLength(lengthAdjusted));
return uninterpretLength;
}

private class UnpackResult {

private final byte[] value;
Expand Down
23 changes: 15 additions & 8 deletions jpos/src/test/java/org/jpos/tlv/packager/EMVTagSequenceTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,14 @@ public void testPacking() throws ISOException, FileNotFoundException, UnknownTag

EMVTagSequence tagValueSequence = new EMVTagSequence();

tagValueSequence.add(new LiteralEMVTag(EMVStandardTagType.APPLICATION_PRIMARY_ACCOUNT_NUMBER_0x5A, "19960930000000"));
tagValueSequence.add(new LiteralEMVTag(EMVStandardTagType.APPLICATION_PRIMARY_ACCOUNT_NUMBER_0x5A, "999999123456789"));

tagValueSequence.add(new LiteralEMVTag(EMVStandardTagType.APPLICATION_PREFERRED_NAME_0x9F12, "JPOS"));

tagValueSequence.add(new LiteralEMVTag(EMVStandardTagType.APPLICATION_LABEL_0x50, "Q2"));

tagValueSequence.add(new LiteralEMVTag(EMVStandardTagType.TRANSACTION_CURRENCY_CODE_0x5F2A, "840"));

ISOMsg field48 = new ISOMsg(48);

tagValueSequence.writeTo(field48);
Expand All @@ -76,9 +78,10 @@ public void testPacking() throws ISOException, FileNotFoundException, UnknownTag
byte[] field48Packed = new byte[packed.length - 12];
System.arraycopy(packed, 12, field48Packed, 0, field48Packed.length);

Assert.assertEquals("Pack error", 23, field48Packed.length);

Assert.assertEquals("Pack error", "303230500251325a07199609300000009f12044a504f53", ISOUtil.byte2hex(field48Packed));
Assert.assertEquals("Pack error", 29, field48Packed.length);
//
Assert.assertEquals("Pack error", "303236500251325a08999999123456789f5f2a0208409f12044a504f53", ISOUtil.byte2hex(field48Packed));
//Assert.assertEquals("Pack error", "303235500251325a079999991234567895f2a0208409f12044a504f53", ISOUtil.byte2hex(field48Packed));

msg = new ISOMsg();
packager.unpack(msg, packed);
Expand All @@ -88,11 +91,11 @@ public void testPacking() throws ISOException, FileNotFoundException, UnknownTag
tagValueSequence = new EMVTagSequence();
tagValueSequence.readFrom((ISOMsg) msg.getComponent(48));

Assert.assertEquals("Unpack error", 3, tagValueSequence.getAll().size());
Assert.assertEquals("Unpack error", 4, tagValueSequence.getAll().size());

String tag1 = EMVStandardTagType.APPLICATION_PRIMARY_ACCOUNT_NUMBER_0x5A.getTagNumberHex();
LiteralEMVTag pan = (LiteralEMVTag) tagValueSequence.getFirst(tag1);
Assert.assertEquals("Unpack error", "19960930000000", pan.getValue());
Assert.assertEquals("Unpack error", "999999123456789", pan.getValue());

String tag2 = EMVStandardTagType.APPLICATION_PREFERRED_NAME_0x9F12.getTagNumberHex();
LiteralEMVTag name = (LiteralEMVTag) tagValueSequence.getFirst(tag2);
Expand All @@ -102,15 +105,19 @@ public void testPacking() throws ISOException, FileNotFoundException, UnknownTag
LiteralEMVTag label = (LiteralEMVTag) tagValueSequence.getFirst(tag3);
Assert.assertEquals("Unpack error", "Q2", label.getValue());

String tag4 = EMVStandardTagType.TRANSACTION_CURRENCY_CODE_0x5F2A.getTagNumberHex();
LiteralEMVTag currency = (LiteralEMVTag) tagValueSequence.getFirst(tag4);
Assert.assertEquals("Unpack error", "840", currency.getValue());

packed = packager.pack(msg);

//skip 4 byte MTI and 8 byte Primary BitMap
field48Packed = new byte[packed.length - 12];
System.arraycopy(packed, 12, field48Packed, 0, field48Packed.length);

Assert.assertEquals("Pack error", 23, field48Packed.length);
Assert.assertEquals("Pack error", 29, field48Packed.length);

Assert.assertEquals("Pack error", "303230500251325a07199609300000009f12044a504f53", ISOUtil.byte2hex(field48Packed));
Assert.assertEquals("Pack error", "303236500251325a08999999123456789f5f2a0208409f12044a504f53", ISOUtil.byte2hex(field48Packed));
}

}

0 comments on commit 4aacb1a

Please sign in to comment.