diff --git a/src/main/java/com/imohsenb/ISO8583/builders/BaseMessageClassBuilder.java b/src/main/java/com/imohsenb/ISO8583/builders/BaseMessageClassBuilder.java index 93616ca..89ff7c1 100644 --- a/src/main/java/com/imohsenb/ISO8583/builders/BaseMessageClassBuilder.java +++ b/src/main/java/com/imohsenb/ISO8583/builders/BaseMessageClassBuilder.java @@ -41,7 +41,7 @@ public BaseMessageClassBuilder(String version, String messageClass) public ISOMessage build() throws ISOException { ISOMessage finalMessage = new ISOMessage(); - finalMessage.setMessage(buildBuffer(true),this.header != null); + finalMessage.setMessage(buildBuffer(),this.header != null); //clear(); @@ -56,23 +56,33 @@ private void clear() dataElements = new TreeMap<>(); } - private byte[] buildBuffer(boolean generateBitmap) - { + private byte[] buildBuffer() throws ISOException { FixedBitSet primaryBitmap = new FixedBitSet(64); + FixedBitSet secondaryBitmap = new FixedBitSet(64); ByteArray dataBuffer = new ByteArray(); for(Map.Entry elem : dataElements.entrySet()) { - if(generateBitmap) + if(elem.getKey()>64) { + secondaryBitmap.flip(elem.getKey() - 65); + + setField(FIELDS.F1_Bitmap, StringUtil.hexStringToByteArray(secondaryBitmap.toHexString())); + } + } + + for(Map.Entry elem : dataElements.entrySet()) { + if(elem.getKey()<=64) primaryBitmap.flip(elem.getKey() - 1); + } + + for(Map.Entry elem : dataElements.entrySet()) { dataBuffer.append(elem.getValue()); } - if(generateBitmap) - dataBuffer.prepend(StringUtil.hexStringToByteArray(primaryBitmap.toHexString())); + dataBuffer.prepend(StringUtil.hexStringToByteArray(primaryBitmap.toHexString())); dataBuffer.prepend(StringUtil.hexStringToByteArray((version + messageClass + messageFunction + messageOrigin))); - if(header!=null && generateBitmap) + if(header!=null) dataBuffer.prepend(StringUtil.hexStringToByteArray(header)); return dataBuffer.array(); @@ -202,6 +212,7 @@ public DataElement setField(int no, String value) throws ISOException { public DataElement setField(FIELDS field, String value) throws ISOException { switch (field.getType()) { + case "a|n": case "n": setField(field,StringUtil.hexStringToByteArray(value),value.length()); break; @@ -218,7 +229,7 @@ public DataElement generateMac(ISOMacGenerator generator) throws ISOExceptio if(generator != null) { - byte[] mac = generator.generate(buildBuffer(true)); + byte[] mac = generator.generate(buildBuffer()); if(mac != null) setField(FIELDS.F64_MAC,mac); else diff --git a/src/main/java/com/imohsenb/ISO8583/entities/ISOMessage.java b/src/main/java/com/imohsenb/ISO8583/entities/ISOMessage.java index cf53cfd..0c6db53 100644 --- a/src/main/java/com/imohsenb/ISO8583/entities/ISOMessage.java +++ b/src/main/java/com/imohsenb/ISO8583/entities/ISOMessage.java @@ -201,13 +201,22 @@ private void parseHeader() { } private void parseBody() { - FixedBitSet pb = new FixedBitSet(64); - pb.fromHexString(StringUtil.fromByteArray(primaryBitmap)); - int offset = 10; + FixedBitSet primaryBitmap = new FixedBitSet(64); + primaryBitmap.fromHexString(StringUtil.fromByteArray(this.primaryBitmap)); + int byteOffset = 10; - for (int o : pb.getIndexes()) { + byteOffset = readFields(primaryBitmap, byteOffset, 0); - FIELDS field = FIELDS.valueOf(o); + byte [] secondaryBitmapBytes = getField(FIELDS.F1_Bitmap); + if(secondaryBitmapBytes != null) { + FixedBitSet secondaryBitmap = new FixedBitSet(64).fromHexString(StringUtil.fromByteArray(secondaryBitmapBytes)); + readFields(secondaryBitmap, byteOffset, 64); + } + } + + private int readFields(FixedBitSet bitmap, int byteOffset, int fieldOffset) { + for (int fieldIndex : bitmap.getIndexes()) { + FIELDS field = FIELDS.valueOf(fieldIndex+fieldOffset); if (field.isFixed()) { int len = field.getLength(); @@ -216,15 +225,14 @@ private void parseBody() { if (len % 2 != 0) len++; len = len / 2; - addElement(field, Arrays.copyOfRange(body, offset, offset + len)); + addElement(field, Arrays.copyOfRange(body, byteOffset, byteOffset + len)); break; default: - addElement(field, Arrays.copyOfRange(body, offset, offset + len)); + addElement(field, Arrays.copyOfRange(body, byteOffset, byteOffset + len)); break; } - offset += len; + byteOffset += len; } else { - int formatLength = 1; switch (field.getFormat()) { case "LL": @@ -236,22 +244,22 @@ private void parseBody() { } int flen = Integer.valueOf( - StringUtil.fromByteArray(Arrays.copyOfRange(body, offset, offset + formatLength))); + StringUtil.fromByteArray(Arrays.copyOfRange(body, byteOffset, byteOffset + formatLength))); switch (field.getType()) { case "z": case "n": - flen /= 2; + flen = flen / 2 + flen % 2; } - offset = offset + formatLength; + byteOffset = byteOffset + formatLength; - addElement(field, Arrays.copyOfRange(body, offset, offset + flen)); + addElement(field, Arrays.copyOfRange(body, byteOffset, byteOffset + flen)); - offset += flen; + byteOffset += flen; } - } + return byteOffset; } private void addElement(FIELDS field, byte[] data) { diff --git a/src/main/java/com/imohsenb/ISO8583/enums/FIELDS.java b/src/main/java/com/imohsenb/ISO8583/enums/FIELDS.java index 270c8b8..bcb6593 100644 --- a/src/main/java/com/imohsenb/ISO8583/enums/FIELDS.java +++ b/src/main/java/com/imohsenb/ISO8583/enums/FIELDS.java @@ -8,7 +8,7 @@ */ public enum FIELDS { // |Field title |no |type |len |fixed |format| - F1_Bitmap (1, "b", 64, true, null), + F1_Bitmap (1, "b", 8, true, null), F2_PAN (2, "n", 19, false, "LL"), F3_ProcessCode (3, "n", 6, true, null), F4_AmountTransaction (4, "n", 12, true, null), @@ -71,7 +71,8 @@ public enum FIELDS { F61_Reserved_Private (61, "ans", 999, false, "LLL"), F62_Reserved_Private (62, "ans", 999, false, "LLL"), F63_Reserved_Private (63, "ans", 999, false, "LLL"), - F64_MAC (64, "b", 16, true, null); + F64_MAC (64, "b", 16, true, null), + F70_Network_Management_Code (70, "n", 3, true, null); diff --git a/src/test/java/com/imohsenb/ISO8583/builders/GeneralMessageClassBuilderTest.java b/src/test/java/com/imohsenb/ISO8583/builders/GeneralMessageClassBuilderTest.java index b207bd3..fe152e0 100644 --- a/src/test/java/com/imohsenb/ISO8583/builders/GeneralMessageClassBuilderTest.java +++ b/src/test/java/com/imohsenb/ISO8583/builders/GeneralMessageClassBuilderTest.java @@ -6,6 +6,7 @@ import com.imohsenb.ISO8583.enums.MESSAGE_ORIGIN; import com.imohsenb.ISO8583.enums.VERSION; import com.imohsenb.ISO8583.exceptions.ISOException; +import com.imohsenb.ISO8583.utils.StringUtil; import org.junit.Test; import static org.assertj.core.api.Assertions.assertThat; @@ -93,4 +94,18 @@ public void OddPanShouldHaveCorrectLengthPrefixAndPaddingChar() throws Exception System.out.println(isoMessage.toString()); assertThat(isoMessage.toString()).isEqualTo("080060000000000000001901234567890123456789920000"); } -} \ No newline at end of file + + @Test + public void AMessageWithASecondaryBitmapIsFormattedCorrectly() throws ISOException { + ISOMessage isoMessage = ISOMessageBuilder.Packer(VERSION.V1987) + .networkManagement() + .setLeftPadding((byte) 0x0) + .mti(MESSAGE_FUNCTION.Request, MESSAGE_ORIGIN.Acquirer) + .processCode("123456") + .setField(FIELDS.F70_Network_Management_Code, "310") + .build(); + System.out.println(isoMessage.toString()); + assertThat(isoMessage.toString()).isEqualTo("0800A00000000000000004000000000000001234560310"); + } +} + diff --git a/src/test/java/com/imohsenb/ISO8583/builders/ISOMessageParseTest.java b/src/test/java/com/imohsenb/ISO8583/builders/ISOMessageParseTest.java new file mode 100644 index 0000000..8d1b9ee --- /dev/null +++ b/src/test/java/com/imohsenb/ISO8583/builders/ISOMessageParseTest.java @@ -0,0 +1,35 @@ +package com.imohsenb.ISO8583.builders; + +import com.imohsenb.ISO8583.entities.ISOMessage; +import com.imohsenb.ISO8583.enums.FIELDS; +import com.imohsenb.ISO8583.exceptions.ISOException; +import com.imohsenb.ISO8583.utils.StringUtil; +import org.junit.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +public class ISOMessageParseTest { + @Test + public void anEvenLengthPanIsParsedCorrectly() throws Exception { + ISOMessage isoMessage = new ISOMessage(); + isoMessage.setMessage(StringUtil.hexStringToByteArray("08006000000000000000161234567890123456920000"), false); + + assertThat(isoMessage.getField(FIELDS.F2_PAN)).isEqualTo(StringUtil.hexStringToByteArray("1234567890123456")); + } + + @Test + public void anOddLengthPanIsParsedCorrectly() throws Exception { + ISOMessage isoMessage = new ISOMessage(); + isoMessage.setMessage(StringUtil.hexStringToByteArray("080060000000000000001901234567890123456789920000"), false); + + assertThat(isoMessage.getField(FIELDS.F2_PAN)).isEqualTo(StringUtil.hexStringToByteArray("01234567890123456789")); + } + + @Test + public void anExtendedFieldIsReadCorrectly() throws ISOException { + ISOMessage isoMessage = new ISOMessage(); + isoMessage.setMessage(StringUtil.hexStringToByteArray("0800A00000000000000004000000000000001234560310"), false); + + assertThat(isoMessage.getField(FIELDS.F70_Network_Management_Code)).isEqualTo(StringUtil.hexStringToByteArray("0310")); + } +}