diff --git a/src/main/java/com/solab/iso8583/MessageFactory.java b/src/main/java/com/solab/iso8583/MessageFactory.java index bfae802..ed94a44 100644 --- a/src/main/java/com/solab/iso8583/MessageFactory.java +++ b/src/main/java/com/solab/iso8583/MessageFactory.java @@ -244,6 +244,7 @@ public class MessageFactory { pos = 10 + isoHeaderLength; } } else { + //ASCII parsing try { for (int i = isoHeaderLength + 4; i < isoHeaderLength + 20; i++) { if (buf[i] >= '0' && buf[i] <= '9') { diff --git a/src/main/java/com/solab/iso8583/parse/AlphaNumericFieldParseInfo.java b/src/main/java/com/solab/iso8583/parse/AlphaNumericFieldParseInfo.java new file mode 100644 index 0000000..d51f868 --- /dev/null +++ b/src/main/java/com/solab/iso8583/parse/AlphaNumericFieldParseInfo.java @@ -0,0 +1,39 @@ +package com.solab.iso8583.parse; + +import java.text.ParseException; + +import com.solab.iso8583.CustomField; +import com.solab.iso8583.IsoType; +import com.solab.iso8583.IsoValue; + +/** This is the common abstract superclass to parse ALPHA and NUMERIC field types. + * + * @author Enrique Zamudio + */ +public abstract class AlphaNumericFieldParseInfo extends FieldParseInfo { + + public AlphaNumericFieldParseInfo(IsoType t, int len) { + super(t, len); + } + + public IsoValue parse(byte[] buf, int pos, CustomField custom) throws ParseException { + if (pos < 0) { + throw new ParseException(String.format("Invalid position %d", pos), pos); + } + if (pos+length > buf.length) { + throw new ParseException(String.format("Insufficient data for %s field of length %d, pos %d", + type, length, pos), pos); + } + if (custom == null) { + System.out.printf("Parseando tipo %s largo %s pos %s: '%s'%n", type, length, pos, new String(buf, pos, length)); + return new IsoValue(type, new String(buf, pos, length), length, null); + } else { + IsoValue v = new IsoValue(type, custom.decodeField(new String(buf, pos, length)), length, custom); + if (v.getValue() == null) { + return new IsoValue(type, new String(buf, pos, length), length, null); + } + return v; + } + } + +} diff --git a/src/main/java/com/solab/iso8583/parse/AlphaParseInfo.java b/src/main/java/com/solab/iso8583/parse/AlphaParseInfo.java new file mode 100644 index 0000000..3b3e1ca --- /dev/null +++ b/src/main/java/com/solab/iso8583/parse/AlphaParseInfo.java @@ -0,0 +1,31 @@ +package com.solab.iso8583.parse; + +import java.text.ParseException; + +import com.solab.iso8583.CustomField; +import com.solab.iso8583.IsoType; +import com.solab.iso8583.IsoValue; + +/** This is the class used to parse ALPHA fields. + * + * @author Enrique Zamudio + */ +public class AlphaParseInfo extends AlphaNumericFieldParseInfo { + + public AlphaParseInfo(int len) { + super(IsoType.ALPHA, len); + } + + public IsoValue parseBinary(byte[] buf, int pos, CustomField custom) throws ParseException { + if (custom == null) { + return new IsoValue(type, new String(buf, pos, length), length, null); + } else { + IsoValue v = new IsoValue(type, custom.decodeField(new String(buf, pos, length)), length, custom); + if (v.getValue() == null) { + return new IsoValue(type, new String(buf, pos, length), length, null); + } + return v; + } + } + +} diff --git a/src/main/java/com/solab/iso8583/parse/AmountParseInfo.java b/src/main/java/com/solab/iso8583/parse/AmountParseInfo.java new file mode 100644 index 0000000..a2e07ed --- /dev/null +++ b/src/main/java/com/solab/iso8583/parse/AmountParseInfo.java @@ -0,0 +1,54 @@ +package com.solab.iso8583.parse; + +import java.math.BigDecimal; +import java.text.ParseException; + +import com.solab.iso8583.CustomField; +import com.solab.iso8583.IsoType; +import com.solab.iso8583.IsoValue; + +/** This class is used to parse AMOUNT fields. + * + * @author Enrique Zamudio + */ +public class AmountParseInfo extends FieldParseInfo { + + + public AmountParseInfo() { + super(IsoType.AMOUNT, 12); + } + + public IsoValue parse(byte[] buf, int pos, CustomField custom) throws ParseException { + if (pos < 0) { + throw new ParseException(String.format("Invalid position %d", pos), pos); + } + if (pos+12 > buf.length) { + throw new ParseException(String.format("Insufficient data for AMOUNT field, pos %d", pos), pos); + } + String c = new String(buf, pos, 12); + try { + return new IsoValue(type, new BigDecimal(c).movePointLeft(2), null); + } catch (NumberFormatException ex) { + throw new ParseException(String.format("Cannot read amount '%s' pos %d", new String(c), pos), pos); + } + } + + public IsoValue parseBinary(byte[] buf, int pos, CustomField custom) throws ParseException { + char[] digits = new char[13]; + digits[10] = '.'; + int start = 0; + for (int i = pos; i < pos + 6; i++) { + digits[start++] = (char)(((buf[i] & 0xf0) >> 4) + 48); + digits[start++] = (char)((buf[i] & 0x0f) + 48); + if (start == 10) { + start++; + } + } + try { + return new IsoValue(IsoType.AMOUNT, new BigDecimal(new String(digits)), null); + } catch (NumberFormatException ex) { + throw new ParseException(String.format("Cannot read amount '%s' pos %d", new String(digits), pos), pos); + } + } + +} diff --git a/src/main/java/com/solab/iso8583/parse/BinaryParseInfo.java b/src/main/java/com/solab/iso8583/parse/BinaryParseInfo.java new file mode 100644 index 0000000..db6a8e3 --- /dev/null +++ b/src/main/java/com/solab/iso8583/parse/BinaryParseInfo.java @@ -0,0 +1,59 @@ +package com.solab.iso8583.parse; + +import java.text.ParseException; + +import com.solab.iso8583.CustomField; +import com.solab.iso8583.IsoType; +import com.solab.iso8583.IsoValue; +import com.solab.iso8583.util.HexCodec; + +/** This class is used to parse fields of type BINARY. + * + * @author Enrique Zamudio + */ +public class BinaryParseInfo extends FieldParseInfo { + + + public BinaryParseInfo(int len) { + super(IsoType.BINARY, len); + } + + @Override + public IsoValue parse(byte[] buf, int pos, CustomField custom) + throws ParseException { + if (pos < 0) { + throw new ParseException(String.format("Invalid position %d", pos), pos); + } + if (pos+(length*2) > buf.length) { + throw new ParseException(String.format("Insufficient data for BINARY field of length %d, pos %d", + length, pos), pos); + } + byte[] binval = HexCodec.hexDecode(new String(buf, pos, length*2)); + if (custom == null) { + return new IsoValue(type, binval, binval.length, null); + } else { + IsoValue v = new IsoValue(type, custom.decodeField(new String(buf, pos, length*2)), length, custom); + if (v.getValue() == null) { + return new IsoValue(type, binval, binval.length, null); + } + return v; + } + } + + @Override + public IsoValue parseBinary(byte[] buf, int pos, + CustomField custom) throws ParseException { + byte[] _v = new byte[length]; + System.arraycopy(buf, pos, _v, 0, length); + if (custom == null) { + return new IsoValue(type, _v, length, null); + } else { + IsoValue v = new IsoValue(type, custom.decodeField(HexCodec.hexEncode(_v)), length, custom); + if (v.getValue() == null) { + return new IsoValue(type, _v, length, null); + } + return v; + } + } + +} diff --git a/src/main/java/com/solab/iso8583/parse/ConfigParser.java b/src/main/java/com/solab/iso8583/parse/ConfigParser.java index 1e79ed6..b03df89 100644 --- a/src/main/java/com/solab/iso8583/parse/ConfigParser.java +++ b/src/main/java/com/solab/iso8583/parse/ConfigParser.java @@ -172,7 +172,7 @@ public class ConfigParser { if (f.getAttribute("length").length() > 0) { length = Integer.parseInt(f.getAttribute("length")); } - parseMap.put(num, new FieldParseInfo(itype, length)); + parseMap.put(num, FieldParseInfo.getInstance(itype, length)); } mfact.setParseMap(type, parseMap); } diff --git a/src/main/java/com/solab/iso8583/parse/Date10ParseInfo.java b/src/main/java/com/solab/iso8583/parse/Date10ParseInfo.java new file mode 100644 index 0000000..c1fea41 --- /dev/null +++ b/src/main/java/com/solab/iso8583/parse/Date10ParseInfo.java @@ -0,0 +1,69 @@ +package com.solab.iso8583.parse; + +import java.text.ParseException; +import java.util.Calendar; +import java.util.Date; + +import com.solab.iso8583.CustomField; +import com.solab.iso8583.IsoType; +import com.solab.iso8583.IsoValue; + +/** This class is used to parse fields of type DATE10. + * + * @author Enrique Zamudio + */ +public class Date10ParseInfo extends FieldParseInfo { + + + public Date10ParseInfo() { + super(IsoType.DATE10, 10); + } + + @Override + public IsoValue parse(byte[] buf, int pos, CustomField custom) + throws ParseException { + if (pos < 0) { + throw new ParseException(String.format("Invalid position %d", pos), pos); + } + if (pos+10 > buf.length) { + throw new ParseException(String.format("Insufficient data for DATE10 field, pos %d", pos), pos); + } + //A SimpleDateFormat in the case of dates won't help because of the missing data + //we have to use the current date for reference and change what comes in the buffer + Calendar cal = Calendar.getInstance(); + //Set the month in the date + cal.set(Calendar.MONTH, ((buf[pos] - 48) * 10) + buf[pos + 1] - 49); + cal.set(Calendar.DATE, ((buf[pos + 2] - 48) * 10) + buf[pos + 3] - 48); + cal.set(Calendar.HOUR_OF_DAY, ((buf[pos + 4] - 48) * 10) + buf[pos + 5] - 48); + cal.set(Calendar.MINUTE, ((buf[pos + 6] - 48) * 10) + buf[pos + 7] - 48); + cal.set(Calendar.SECOND, ((buf[pos + 8] - 48) * 10) + buf[pos + 9] - 48); + if (cal.getTime().after(new Date())) { + cal.add(Calendar.YEAR, -1); + } + return new IsoValue(type, cal.getTime(), null); + } + + @Override + public IsoValue parseBinary(byte[] buf, int pos, + CustomField custom) throws ParseException { + int[] tens = new int[5]; + int start = 0; + for (int i = pos; i < pos + tens.length; i++) { + tens[start++] = (((buf[i] & 0xf0) >> 4) * 10) + (buf[i] & 0x0f); + } + Calendar cal = Calendar.getInstance(); + //A SimpleDateFormat in the case of dates won't help because of the missing data + //we have to use the current date for reference and change what comes in the buffer + //Set the month in the date + cal.set(Calendar.MONTH, tens[0] - 1); + cal.set(Calendar.DATE, tens[1]); + cal.set(Calendar.HOUR_OF_DAY, tens[2]); + cal.set(Calendar.MINUTE, tens[3]); + cal.set(Calendar.SECOND, tens[4]); + if (cal.getTime().after(new Date())) { + cal.add(Calendar.YEAR, -1); + } + return new IsoValue(type, cal.getTime(), null); + } + +} diff --git a/src/main/java/com/solab/iso8583/parse/Date4ParseInfo.java b/src/main/java/com/solab/iso8583/parse/Date4ParseInfo.java new file mode 100644 index 0000000..5792579 --- /dev/null +++ b/src/main/java/com/solab/iso8583/parse/Date4ParseInfo.java @@ -0,0 +1,64 @@ +package com.solab.iso8583.parse; + +import java.text.ParseException; +import java.util.Calendar; +import java.util.Date; + +import com.solab.iso8583.CustomField; +import com.solab.iso8583.IsoType; +import com.solab.iso8583.IsoValue; + +/** This class is used to parse fields of type DATE4. + * + * @author Enrique Zamudio + */ +public class Date4ParseInfo extends FieldParseInfo { + + public Date4ParseInfo() { + super(IsoType.DATE4, 4); + } + + @Override + public IsoValue parse(byte[] buf, int pos, CustomField custom) + throws ParseException { + if (pos < 0) { + throw new ParseException(String.format("Invalid position %d", pos), pos); + } + if (pos+4 > buf.length) { + throw new ParseException(String.format("Insufficient data for DATE4 field, pos %d", pos), pos); + } + Calendar cal = Calendar.getInstance(); + cal.set(Calendar.HOUR, 0); + cal.set(Calendar.MINUTE, 0); + cal.set(Calendar.SECOND, 0); + //Set the month in the date + cal.set(Calendar.MONTH, ((buf[pos] - 48) * 10) + buf[pos + 1] - 49); + cal.set(Calendar.DATE, ((buf[pos + 2] - 48) * 10) + buf[pos + 3] - 48); + if (cal.getTime().after(new Date())) { + cal.add(Calendar.YEAR, -1); + } + return new IsoValue(type, cal.getTime(), null); + } + + @Override + public IsoValue parseBinary(byte[] buf, int pos, + CustomField custom) throws ParseException { + int[] tens = new int[2]; + int start = 0; + for (int i = pos; i < pos + tens.length; i++) { + tens[start++] = (((buf[i] & 0xf0) >> 4) * 10) + (buf[i] & 0x0f); + } + Calendar cal = Calendar.getInstance(); + cal.set(Calendar.HOUR, 0); + cal.set(Calendar.MINUTE, 0); + cal.set(Calendar.SECOND, 0); + //Set the month in the date + cal.set(Calendar.MONTH, tens[0] - 1); + cal.set(Calendar.DATE, tens[1]); + if (cal.getTime().after(new Date())) { + cal.add(Calendar.YEAR, -1); + } + return new IsoValue(type, cal.getTime(), null); + } + +} diff --git a/src/main/java/com/solab/iso8583/parse/DateExpParseInfo.java b/src/main/java/com/solab/iso8583/parse/DateExpParseInfo.java new file mode 100644 index 0000000..e338798 --- /dev/null +++ b/src/main/java/com/solab/iso8583/parse/DateExpParseInfo.java @@ -0,0 +1,61 @@ +package com.solab.iso8583.parse; + +import java.text.ParseException; +import java.util.Calendar; +import java.util.Date; + +import com.solab.iso8583.CustomField; +import com.solab.iso8583.IsoType; +import com.solab.iso8583.IsoValue; + +/** This class is used to parse fields of type DATE_EXP. + * + * @author Enrique Zamudio + */ +public class DateExpParseInfo extends FieldParseInfo { + + public DateExpParseInfo() { + super(IsoType.DATE_EXP, 4); + } + + @Override + public IsoValue parse(byte[] buf, int pos, CustomField custom) + throws ParseException { + if (pos < 0) { + throw new ParseException(String.format("Invalid position %d", pos), pos); + } + if (pos+4 > buf.length) { + throw new ParseException(String.format("Insufficient data for DATE_EXP field, pos %d", pos), pos); + } + Calendar cal = Calendar.getInstance(); + cal.set(Calendar.HOUR, 0); + cal.set(Calendar.MINUTE, 0); + cal.set(Calendar.SECOND, 0); + cal.set(Calendar.DATE, 1); + //Set the month in the date + cal.set(Calendar.YEAR, cal.get(Calendar.YEAR) - (cal.get(Calendar.YEAR) % 100) + + ((buf[pos] - 48) * 10) + buf[pos + 1] - 48); + cal.set(Calendar.MONTH, ((buf[pos + 2] - 48) * 10) + buf[pos + 3] - 49); + return new IsoValue(type, cal.getTime(), null); + } + + @Override + public IsoValue parseBinary(byte[] buf, int pos, + CustomField custom) throws ParseException { + int[] tens = new int[2]; + int start = 0; + for (int i = pos; i < pos + tens.length; i++) { + tens[start++] = (((buf[i] & 0xf0) >> 4) * 10) + (buf[i] & 0x0f); + } + Calendar cal = Calendar.getInstance(); + cal.set(Calendar.HOUR, 0); + cal.set(Calendar.MINUTE, 0); + cal.set(Calendar.SECOND, 0); + cal.set(Calendar.DATE, 1); + //Set the month in the date + cal.set(Calendar.YEAR, cal.get(Calendar.YEAR) + - (cal.get(Calendar.YEAR) % 100) + tens[0]); + cal.set(Calendar.MONTH, tens[1] - 1); + return new IsoValue(type, cal.getTime(), null); + } +} diff --git a/src/main/java/com/solab/iso8583/parse/FieldParseInfo.java b/src/main/java/com/solab/iso8583/parse/FieldParseInfo.java index f783649..0859d39 100644 --- a/src/main/java/com/solab/iso8583/parse/FieldParseInfo.java +++ b/src/main/java/com/solab/iso8583/parse/FieldParseInfo.java @@ -18,25 +18,20 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ package com.solab.iso8583.parse; -import java.math.BigDecimal; -import java.math.BigInteger; import java.text.ParseException; -import java.util.Calendar; -import java.util.Date; import com.solab.iso8583.CustomField; import com.solab.iso8583.IsoType; import com.solab.iso8583.IsoValue; -import com.solab.iso8583.util.HexCodec; -/** This class contains the information needed to parse a field from a message buffer. +/** This class is used to parse a field from a message buffer. There are concrete subclasses for each IsoType. * * @author Enrique Zamudio */ -public class FieldParseInfo { +public abstract class FieldParseInfo { - private IsoType type; - private int length; + protected IsoType type; + protected int length; /** Creates a new instance that parses a value of the specified type, with the specified length. * The length is only useful for ALPHA and NUMERIC types. @@ -62,396 +57,40 @@ public class FieldParseInfo { /** Parses the character data from the buffer and returns the * IsoValue with the correct data type in it. */ - public IsoValue parse(byte[] buf, int pos, CustomField custom) throws ParseException { - if (pos < 0) { - throw new ParseException(String.format("Invalid position %d", pos), pos); - } - if (type == IsoType.NUMERIC || type == IsoType.ALPHA) { - if (pos+length > buf.length) { - throw new ParseException(String.format("Insufficient data for ALPHA or NUMERIC field of length %d, pos %d", - length, pos), pos); - } - if (custom == null) { - return new IsoValue(type, new String(buf, pos, length), length, null); - } else { - IsoValue v = new IsoValue(type, custom.decodeField(new String(buf, pos, length)), length, custom); - if (v.getValue() == null) { - return new IsoValue(type, new String(buf, pos, length), length, null); - } - return v; - } - } else if (type == IsoType.LLVAR) { - length = ((buf[pos] - 48) * 10) + (buf[pos + 1] - 48); - if (length < 0) { - throw new ParseException(String.format("Invalid LLVAR length %d pos %d", length, pos), pos); - } - if (pos+2 > buf.length || length+pos+2 > buf.length) { - throw new ParseException(String.format("Insufficient data for LLVAR field, pos %d", pos), pos); - } - String _v = length == 0 ? "" : new String(buf, pos + 2, length); - if (custom == null) { - return new IsoValue(type, _v, length, null); - } else { - IsoValue v = new IsoValue(type, custom.decodeField(_v), length, custom); - if (v.getValue() == null) { - return new IsoValue(type, _v, length, null); - } - return v; - } - } else if (type == IsoType.LLLVAR) { - if (!(Character.isDigit(buf[pos]) && Character.isDigit(buf[pos+1]) && Character.isDigit(buf[pos+2]))) { - throw new ParseException(String.format("Invalid LLLVAR length '%s' pos %d", - new String(buf, pos, 3), pos), pos); - } - length = ((buf[pos] - 48) * 100) + ((buf[pos + 1] - 48) * 10) + (buf[pos + 2] - 48); - if (length < 0) { - throw new ParseException(String.format("Invalid LLLVAR length %d pos %d", length, pos), pos); - } - if (length+pos+3 > buf.length) { - throw new ParseException(String.format("Insufficient data for LLLVAR field, pos %d", pos), pos); - } - String _v = length == 0 ? "" : new String(buf, pos + 3, length); - if (custom == null) { - return new IsoValue(type, _v, length, null); - } else { - IsoValue v = new IsoValue(type, custom.decodeField(_v), length, custom); - if (v.getValue() == null) { - //problems decoding? return the string - return new IsoValue(type, _v, length, null); - } - return v; - } - } else if (type == IsoType.AMOUNT) { - if (pos+12 > buf.length) { - throw new ParseException(String.format("Insufficient data for AMOUNT field of length %d, pos %d", - length, pos), pos); - } - String c = new String(buf, pos, 12); - try { - return new IsoValue(type, new BigDecimal(c).movePointLeft(2), null); - } catch (NumberFormatException ex) { - throw new ParseException(String.format("Cannot read amount '%s' pos %d", new String(c), pos), pos); - } - } else if (type == IsoType.DATE10) { - if (pos+10 > buf.length) { - throw new ParseException(String.format("Insufficient data for DATE10 field of length %d, pos %d", - length, pos), pos); - } - //A SimpleDateFormat in the case of dates won't help because of the missing data - //we have to use the current date for reference and change what comes in the buffer - Calendar cal = Calendar.getInstance(); - //Set the month in the date - cal.set(Calendar.MONTH, ((buf[pos] - 48) * 10) + buf[pos + 1] - 49); - cal.set(Calendar.DATE, ((buf[pos + 2] - 48) * 10) + buf[pos + 3] - 48); - cal.set(Calendar.HOUR_OF_DAY, ((buf[pos + 4] - 48) * 10) + buf[pos + 5] - 48); - cal.set(Calendar.MINUTE, ((buf[pos + 6] - 48) * 10) + buf[pos + 7] - 48); - cal.set(Calendar.SECOND, ((buf[pos + 8] - 48) * 10) + buf[pos + 9] - 48); - if (cal.getTime().after(new Date())) { - cal.add(Calendar.YEAR, -1); - } - return new IsoValue(type, cal.getTime(), null); - } else if (type == IsoType.DATE4) { - if (pos+4 > buf.length) { - throw new ParseException(String.format("Insufficient data for DATE4 field of length %d, pos %d", - length, pos), pos); - } - Calendar cal = Calendar.getInstance(); - cal.set(Calendar.HOUR, 0); - cal.set(Calendar.MINUTE, 0); - cal.set(Calendar.SECOND, 0); - //Set the month in the date - cal.set(Calendar.MONTH, ((buf[pos] - 48) * 10) + buf[pos + 1] - 49); - cal.set(Calendar.DATE, ((buf[pos + 2] - 48) * 10) + buf[pos + 3] - 48); - if (cal.getTime().after(new Date())) { - cal.add(Calendar.YEAR, -1); - } - return new IsoValue(type, cal.getTime(), null); - } else if (type == IsoType.DATE_EXP) { - Calendar cal = Calendar.getInstance(); - cal.set(Calendar.HOUR, 0); - cal.set(Calendar.MINUTE, 0); - cal.set(Calendar.SECOND, 0); - cal.set(Calendar.DATE, 1); - //Set the month in the date - cal.set(Calendar.YEAR, cal.get(Calendar.YEAR) - (cal.get(Calendar.YEAR) % 100) - + ((buf[pos] - 48) * 10) + buf[pos + 1] - 48); - cal.set(Calendar.MONTH, ((buf[pos + 2] - 48) * 10) + buf[pos + 3] - 49); - return new IsoValue(type, cal.getTime(), null); - } else if (type == IsoType.TIME) { - Calendar cal = Calendar.getInstance(); - cal.set(Calendar.HOUR_OF_DAY, ((buf[pos] - 48) * 10) + buf[pos + 1] - 48); - cal.set(Calendar.MINUTE, ((buf[pos + 2] - 48) * 10) + buf[pos + 3] - 48); - cal.set(Calendar.SECOND, ((buf[pos + 4] - 48) * 10) + buf[pos + 5] - 48); - return new IsoValue(type, cal.getTime(), null); - - } else if (type == IsoType.BINARY) { - - if (pos+(length*2) > buf.length) { - throw new ParseException(String.format("Insufficient data for BINARY field of length %d, pos %d", - length, pos), pos); - } - byte[] binval = HexCodec.hexDecode(new String(buf, pos, length*2)); - if (custom == null) { - return new IsoValue(type, binval, binval.length, null); - } else { - IsoValue v = new IsoValue(type, custom.decodeField(new String(buf, pos, length*2)), length, custom); - if (v.getValue() == null) { - return new IsoValue(type, binval, binval.length, null); - } - return v; - } - - } else if (type == IsoType.LLBIN) { - - length = ((buf[pos] - 48) * 10) + (buf[pos + 1] - 48); - if (length < 0) { - throw new ParseException(String.format("Invalid LLBIN length %d pos %d", length, pos), pos); - } - if (pos+2 > buf.length || length+pos+2 > buf.length) { - throw new ParseException(String.format("Insufficient data for LLBIN field, pos %d", pos), pos); - } - byte[] binval = length == 0 ? new byte[0] : HexCodec.hexDecode(new String(buf, pos + 2, length)); - if (custom == null) { - return new IsoValue(type, binval, binval.length, null); - } else { - IsoValue v = new IsoValue(type, custom.decodeField( - new String(buf, pos + 2, length)), binval.length, custom); - if (v.getValue() == null) { - return new IsoValue(type, binval, binval.length, null); - } - return v; - } - - } else if (type == IsoType.LLLBIN) { - - if (!(Character.isDigit(buf[pos]) && Character.isDigit(buf[pos+1]) && Character.isDigit(buf[pos+2]))) { - throw new ParseException(String.format("Invalid LLLBIN length '%s' pos %d", new String(buf, pos, 3), pos), pos); - } - length = ((buf[pos] - 48) * 100) + ((buf[pos + 1] - 48) * 10) + (buf[pos + 2] - 48); - if (length < 0) { - throw new ParseException(String.format("Invalid LLLBIN length %d pos %d", length, pos), pos); - } - if (length+pos+3 > buf.length) { - throw new ParseException(String.format("Insufficient data for LLLBIN field, pos %d", pos), pos); - } - byte[] binval = length == 0 ? new byte[0] : HexCodec.hexDecode(new String(buf, pos + 3, length)); - if (custom == null) { - return new IsoValue(type, binval, binval.length, null); - } else { - IsoValue v = new IsoValue(type, custom.decodeField( - length == 0 ? "" : new String(buf, pos + 3, length)), length, custom); - if (v.getValue() == null) { - //problems decoding? return the string - return new IsoValue(type, binval, binval.length, null); - } - return v; - } - } - return null; - } + public abstract IsoValue parse(byte[] buf, int pos, CustomField custom) throws ParseException; /** Parses binary data from the buffer, creating and returning an IsoValue of the configured * type and length. */ - public IsoValue parseBinary(byte[] buf, int pos, CustomField custom) throws ParseException { - if (type == IsoType.ALPHA) { - - if (custom == null) { - return new IsoValue(type, new String(buf, pos, length), length, null); - } else { - IsoValue v = new IsoValue(type, custom.decodeField(new String(buf, pos, length)), length, custom); - if (v.getValue() == null) { - return new IsoValue(type, new String(buf, pos, length), length, null); - } - return v; - } - - } else if (type == IsoType.NUMERIC) { - - //A long covers up to 18 digits - if (length < 19) { - long l = 0; - long power = 1L; - for (int i = pos + (length / 2) + (length % 2) - 1; i >= pos; i--) { - l += (buf[i] & 0x0f) * power; - power *= 10L; - l += ((buf[i] & 0xf0) >> 4) * power; - power *= 10L; - } - return new IsoValue(IsoType.NUMERIC, l, length, null); - } else { - //Use a BigInteger - char[] digits = new char[length]; - int start = 0; - for (int i = pos; i < pos + (length / 2) + (length % 2); i++) { - digits[start++] = (char)(((buf[i] & 0xf0) >> 4) + 48); - digits[start++] = (char)((buf[i] & 0x0f) + 48); - } - return new IsoValue(IsoType.NUMERIC, new BigInteger(new String(digits)), length, null); - } - - } else if (type == IsoType.LLVAR) { - - length = (((buf[pos] & 0xf0) >> 4) * 10) + (buf[pos] & 0x0f); - if (length < 0) { - throw new ParseException(String.format("Invalid LLVAR length %d pos %d", length, pos), pos); - } - if (pos+1 > buf.length || length+pos+1 > buf.length) { - throw new ParseException(String.format("Insufficient data for LLVAR field, pos %d", pos), pos); - } - if (custom == null) { - return new IsoValue(type, new String(buf, pos + 1, length), null); - } else { - IsoValue v = new IsoValue(type, custom.decodeField(new String(buf, pos + 1, length)), custom); - if (v.getValue() == null) { - return new IsoValue(type, new String(buf, pos + 1, length), null); - } - return v; - } - - } else if (type == IsoType.LLLVAR) { - - length = ((buf[pos] & 0x0f) * 100) + (((buf[pos + 1] & 0xf0) >> 4) * 10) + (buf[pos + 1] & 0x0f); - if (length < 0) { - throw new ParseException(String.format("Invalid LLLVAR length %d pos %d", length, pos), pos); - } - if (length+pos+2 > buf.length) { - throw new ParseException(String.format("Insufficient data for LLLVAR field, pos %d", pos), pos); - } - if (custom == null) { - return new IsoValue(type, new String(buf, pos + 2, length), null); - } else { - IsoValue v = new IsoValue(type, custom.decodeField(new String(buf, pos + 2, length)), custom); - if (v.getValue() == null) { - return new IsoValue(type, new String(buf, pos + 2, length), null); - } - return v; - } - - } else if (type == IsoType.AMOUNT) { - - char[] digits = new char[13]; - digits[10] = '.'; - int start = 0; - for (int i = pos; i < pos + 6; i++) { - digits[start++] = (char)(((buf[i] & 0xf0) >> 4) + 48); - digits[start++] = (char)((buf[i] & 0x0f) + 48); - if (start == 10) { - start++; - } - } - try { - return new IsoValue(IsoType.AMOUNT, new BigDecimal(new String(digits)), null); - } catch (NumberFormatException ex) { - throw new ParseException(String.format("Cannot read amount '%s' pos %d", new String(digits), pos), pos); - } - } else if (type == IsoType.DATE10 || type == IsoType.DATE4 || type == IsoType.DATE_EXP - || type == IsoType.TIME) { - - int[] tens = new int[(type.getLength() / 2) + (type.getLength() % 2)]; - int start = 0; - for (int i = pos; i < pos + tens.length; i++) { - tens[start++] = (((buf[i] & 0xf0) >> 4) * 10) + (buf[i] & 0x0f); - } - Calendar cal = Calendar.getInstance(); - if (type == IsoType.DATE10) { - //A SimpleDateFormat in the case of dates won't help because of the missing data - //we have to use the current date for reference and change what comes in the buffer - //Set the month in the date - cal.set(Calendar.MONTH, tens[0] - 1); - cal.set(Calendar.DATE, tens[1]); - cal.set(Calendar.HOUR_OF_DAY, tens[2]); - cal.set(Calendar.MINUTE, tens[3]); - cal.set(Calendar.SECOND, tens[4]); - if (cal.getTime().after(new Date())) { - cal.add(Calendar.YEAR, -1); - } - return new IsoValue(type, cal.getTime(), null); - } else if (type == IsoType.DATE4) { - cal.set(Calendar.HOUR, 0); - cal.set(Calendar.MINUTE, 0); - cal.set(Calendar.SECOND, 0); - //Set the month in the date - cal.set(Calendar.MONTH, tens[0] - 1); - cal.set(Calendar.DATE, tens[1]); - if (cal.getTime().after(new Date())) { - cal.add(Calendar.YEAR, -1); - } - return new IsoValue(type, cal.getTime(), null); - } else if (type == IsoType.DATE_EXP) { - cal.set(Calendar.HOUR, 0); - cal.set(Calendar.MINUTE, 0); - cal.set(Calendar.SECOND, 0); - cal.set(Calendar.DATE, 1); - //Set the month in the date - cal.set(Calendar.YEAR, cal.get(Calendar.YEAR) - - (cal.get(Calendar.YEAR) % 100) + tens[0]); - cal.set(Calendar.MONTH, tens[1] - 1); - return new IsoValue(type, cal.getTime(), null); - } else if (type == IsoType.TIME) { - cal.set(Calendar.HOUR_OF_DAY, tens[0]); - cal.set(Calendar.MINUTE, tens[1]); - cal.set(Calendar.SECOND, tens[2]); - return new IsoValue(type, cal.getTime(), null); - } - return new IsoValue(type, cal.getTime(), null); - } else if (type == IsoType.BINARY) { - - byte[] _v = new byte[length]; - System.arraycopy(buf, pos, _v, 0, length); - if (custom == null) { - return new IsoValue(type, _v, length, null); - } else { - IsoValue v = new IsoValue(type, custom.decodeField(HexCodec.hexEncode(_v)), length, custom); - if (v.getValue() == null) { - return new IsoValue(type, _v, length, null); - } - return v; - } - - } else if (type == IsoType.LLBIN) { - - length = (((buf[pos] & 0xf0) >> 4) * 10) + (buf[pos] & 0x0f); - if (length < 0) { - throw new ParseException(String.format("Invalid LLBIN length %d pos %d", length, pos), pos); - } - if (pos+1 > buf.length || length+pos+1 > buf.length) { - throw new ParseException(String.format("Insufficient data for LLBIN field, pos %d", pos), pos); - } - byte[] _v = new byte[length]; - System.arraycopy(buf, pos+1, _v, 0, length); - if (custom == null) { - return new IsoValue(type, _v, null); - } else { - IsoValue v = new IsoValue(type, custom.decodeField(HexCodec.hexEncode(_v)), custom); - if (v.getValue() == null) { - return new IsoValue(type, _v, null); - } - return v; - } - - } else if (type == IsoType.LLLBIN) { - - length = ((buf[pos] & 0x0f) * 100) + (((buf[pos + 1] & 0xf0) >> 4) * 10) + (buf[pos + 1] & 0x0f); - if (length < 0) { - throw new ParseException(String.format("Invalid LLLBIN length %d pos %d", length, pos), pos); - } - if (length+pos+2 > buf.length) { - throw new ParseException(String.format("Insufficient data for LLLBIN field, pos %d", pos), pos); - } - byte[] _v = new byte[length]; - System.arraycopy(buf, pos+2, _v, 0, length); - if (custom == null) { - return new IsoValue(type, _v, null); - } else { - IsoValue v = new IsoValue(type, custom.decodeField(HexCodec.hexEncode(_v)), custom); - if (v.getValue() == null) { - return new IsoValue(type, _v, null); - } - return v; - } + public abstract IsoValue parseBinary(byte[] buf, int pos, CustomField custom) throws ParseException; + /** Returns a new FieldParseInfo instance that can parse the specified type. */ + public static FieldParseInfo getInstance(IsoType t, int len) { + if (t == IsoType.ALPHA) { + return new AlphaParseInfo(len); + } else if (t == IsoType.AMOUNT) { + return new AmountParseInfo(); + } else if (t == IsoType.BINARY) { + return new BinaryParseInfo(len); + } else if (t == IsoType.DATE10) { + return new Date10ParseInfo(); + } else if (t == IsoType.DATE4) { + return new Date4ParseInfo(); + } else if (t == IsoType.DATE_EXP) { + return new DateExpParseInfo(); + } else if (t == IsoType.LLBIN) { + return new LlbinParseInfo(); + } else if (t == IsoType.LLLBIN) { + return new LllbinParseInfo(); + } else if (t == IsoType.LLLVAR) { + return new LllvarParseInfo(); + } else if (t == IsoType.LLVAR) { + return new LlvarParseInfo(); + } else if (t == IsoType.NUMERIC) { + return new NumericParseInfo(len); + } else if (t == IsoType.TIME) { + return new TimeParseInfo(); } - return null; + throw new IllegalArgumentException(String.format("Cannot parse type %s", t)); } } diff --git a/src/main/java/com/solab/iso8583/parse/LlbinParseInfo.java b/src/main/java/com/solab/iso8583/parse/LlbinParseInfo.java new file mode 100644 index 0000000..54f4f5e --- /dev/null +++ b/src/main/java/com/solab/iso8583/parse/LlbinParseInfo.java @@ -0,0 +1,70 @@ +package com.solab.iso8583.parse; + +import java.text.ParseException; + +import com.solab.iso8583.CustomField; +import com.solab.iso8583.IsoType; +import com.solab.iso8583.IsoValue; +import com.solab.iso8583.util.HexCodec; + +/** This class is used to parse fields of type LLBIN. + * + * @author Enrique Zamudio + */ +public class LlbinParseInfo extends FieldParseInfo { + + + public LlbinParseInfo() { + super(IsoType.LLBIN, 0); + } + + @Override + public IsoValue parse(byte[] buf, int pos, CustomField custom) + throws ParseException { + if (pos < 0) { + throw new ParseException(String.format("Invalid position %d", pos), pos); + } + length = ((buf[pos] - 48) * 10) + (buf[pos + 1] - 48); + if (length < 0) { + throw new ParseException(String.format("Invalid LLBIN length %d pos %d", length, pos), pos); + } + if (pos+2 > buf.length || length+pos+2 > buf.length) { + throw new ParseException(String.format("Insufficient data for LLBIN field, pos %d", pos), pos); + } + byte[] binval = length == 0 ? new byte[0] : HexCodec.hexDecode(new String(buf, pos + 2, length)); + if (custom == null) { + return new IsoValue(type, binval, binval.length, null); + } else { + IsoValue v = new IsoValue(type, custom.decodeField( + new String(buf, pos + 2, length)), binval.length, custom); + if (v.getValue() == null) { + return new IsoValue(type, binval, binval.length, null); + } + return v; + } + } + + @Override + public IsoValue parseBinary(byte[] buf, int pos, + CustomField custom) throws ParseException { + length = (((buf[pos] & 0xf0) >> 4) * 10) + (buf[pos] & 0x0f); + if (length < 0) { + throw new ParseException(String.format("Invalid LLBIN length %d pos %d", length, pos), pos); + } + if (pos+1 > buf.length || length+pos+1 > buf.length) { + throw new ParseException(String.format("Insufficient data for LLBIN field, pos %d", pos), pos); + } + byte[] _v = new byte[length]; + System.arraycopy(buf, pos+1, _v, 0, length); + if (custom == null) { + return new IsoValue(type, _v, null); + } else { + IsoValue v = new IsoValue(type, custom.decodeField(HexCodec.hexEncode(_v)), custom); + if (v.getValue() == null) { + return new IsoValue(type, _v, null); + } + return v; + } + } + +} diff --git a/src/main/java/com/solab/iso8583/parse/LllbinParseInfo.java b/src/main/java/com/solab/iso8583/parse/LllbinParseInfo.java new file mode 100644 index 0000000..8cda398 --- /dev/null +++ b/src/main/java/com/solab/iso8583/parse/LllbinParseInfo.java @@ -0,0 +1,74 @@ +package com.solab.iso8583.parse; + +import java.text.ParseException; + +import com.solab.iso8583.CustomField; +import com.solab.iso8583.IsoType; +import com.solab.iso8583.IsoValue; +import com.solab.iso8583.util.HexCodec; + +/** This class is used to parse fields of type LLLBIN. + * + * @author Enrique Zamudio + */ +public class LllbinParseInfo extends FieldParseInfo { + + + public LllbinParseInfo() { + super(IsoType.LLLBIN, 0); + } + + @Override + public IsoValue parse(byte[] buf, int pos, CustomField custom) + throws ParseException { + if (pos < 0) { + throw new ParseException(String.format("Invalid position %d", pos), pos); + } + if (!(Character.isDigit(buf[pos]) && Character.isDigit(buf[pos+1]) && Character.isDigit(buf[pos+2]))) { + throw new ParseException(String.format("Invalid LLLBIN length '%s' pos %d", new String(buf, pos, 3), pos), pos); + } + length = ((buf[pos] - 48) * 100) + ((buf[pos + 1] - 48) * 10) + (buf[pos + 2] - 48); + if (length < 0) { + throw new ParseException(String.format("Invalid LLLBIN length %d pos %d", length, pos), pos); + } + if (length+pos+3 > buf.length) { + throw new ParseException(String.format("Insufficient data for LLLBIN field, pos %d", pos), pos); + } + byte[] binval = length == 0 ? new byte[0] : HexCodec.hexDecode(new String(buf, pos + 3, length)); + if (custom == null) { + return new IsoValue(type, binval, binval.length, null); + } else { + IsoValue v = new IsoValue(type, custom.decodeField( + length == 0 ? "" : new String(buf, pos + 3, length)), length, custom); + if (v.getValue() == null) { + //problems decoding? return the string + return new IsoValue(type, binval, binval.length, null); + } + return v; + } + } + + @Override + public IsoValue parseBinary(byte[] buf, int pos, + CustomField custom) throws ParseException { + length = ((buf[pos] & 0x0f) * 100) + (((buf[pos + 1] & 0xf0) >> 4) * 10) + (buf[pos + 1] & 0x0f); + if (length < 0) { + throw new ParseException(String.format("Invalid LLLBIN length %d pos %d", length, pos), pos); + } + if (length+pos+2 > buf.length) { + throw new ParseException(String.format("Insufficient data for LLLBIN field, pos %d", pos), pos); + } + byte[] _v = new byte[length]; + System.arraycopy(buf, pos+2, _v, 0, length); + if (custom == null) { + return new IsoValue(type, _v, null); + } else { + IsoValue v = new IsoValue(type, custom.decodeField(HexCodec.hexEncode(_v)), custom); + if (v.getValue() == null) { + return new IsoValue(type, _v, null); + } + return v; + } + } + +} diff --git a/src/main/java/com/solab/iso8583/parse/LllvarParseInfo.java b/src/main/java/com/solab/iso8583/parse/LllvarParseInfo.java new file mode 100644 index 0000000..181545b --- /dev/null +++ b/src/main/java/com/solab/iso8583/parse/LllvarParseInfo.java @@ -0,0 +1,67 @@ +package com.solab.iso8583.parse; + +import java.text.ParseException; + +import com.solab.iso8583.CustomField; +import com.solab.iso8583.IsoType; +import com.solab.iso8583.IsoValue; + +/** This class is used to parse fields of type LLLVAR. + * + * @author Enrique Zamudio + */ +public class LllvarParseInfo extends FieldParseInfo { + + + public LllvarParseInfo() { + super(IsoType.LLLVAR, 0); + } + + public IsoValue parse(byte[] buf, int pos, CustomField custom) throws ParseException { + if (pos < 0) { + throw new ParseException(String.format("Invalid position %d", pos), pos); + } + if (!(Character.isDigit(buf[pos]) && Character.isDigit(buf[pos+1]) && Character.isDigit(buf[pos+2]))) { + throw new ParseException(String.format("Invalid LLLVAR length '%s' pos %d", + new String(buf, pos, 3), pos), pos); + } + length = ((buf[pos] - 48) * 100) + ((buf[pos + 1] - 48) * 10) + (buf[pos + 2] - 48); + if (length < 0) { + throw new ParseException(String.format("Invalid LLLVAR length %d pos %d", length, pos), pos); + } + if (length+pos+3 > buf.length) { + throw new ParseException(String.format("Insufficient data for LLLVAR field, pos %d", pos), pos); + } + String _v = length == 0 ? "" : new String(buf, pos + 3, length); + if (custom == null) { + return new IsoValue(type, _v, length, null); + } else { + IsoValue v = new IsoValue(type, custom.decodeField(_v), length, custom); + if (v.getValue() == null) { + //problems decoding? return the string + return new IsoValue(type, _v, length, null); + } + return v; + } + } + + public IsoValue parseBinary(byte[] buf, int pos, CustomField custom) throws ParseException { + length = ((buf[pos] & 0x0f) * 100) + (((buf[pos + 1] & 0xf0) >> 4) * 10) + (buf[pos + 1] & 0x0f); + if (length < 0) { + throw new ParseException(String.format("Invalid LLLVAR length %d pos %d", length, pos), pos); + } + if (length+pos+2 > buf.length) { + throw new ParseException(String.format("Insufficient data for LLLVAR field, pos %d", pos), pos); + } + if (custom == null) { + return new IsoValue(type, new String(buf, pos + 2, length), null); + } else { + IsoValue v = new IsoValue(type, custom.decodeField(new String(buf, pos + 2, length)), custom); + if (v.getValue() == null) { + return new IsoValue(type, new String(buf, pos + 2, length), null); + } + return v; + } + } + +} diff --git a/src/main/java/com/solab/iso8583/parse/LlvarParseInfo.java b/src/main/java/com/solab/iso8583/parse/LlvarParseInfo.java new file mode 100644 index 0000000..886f6d4 --- /dev/null +++ b/src/main/java/com/solab/iso8583/parse/LlvarParseInfo.java @@ -0,0 +1,62 @@ +package com.solab.iso8583.parse; + +import java.text.ParseException; + +import com.solab.iso8583.CustomField; +import com.solab.iso8583.IsoType; +import com.solab.iso8583.IsoValue; + +/** This class is used to parse fields of type LLVAR. + * + * @author Enrique Zamudio + */ +public class LlvarParseInfo extends FieldParseInfo { + + public LlvarParseInfo() { + super(IsoType.LLVAR, 0); + } + + public IsoValue parse(byte[] buf, int pos, CustomField custom) throws ParseException { + if (pos < 0) { + throw new ParseException(String.format("Invalid position %d", pos), pos); + } + length = ((buf[pos] - 48) * 10) + (buf[pos + 1] - 48); + if (length < 0) { + throw new ParseException(String.format("Invalid LLVAR length %d pos %d", length, pos), pos); + } + if (pos+2 > buf.length || length+pos+2 > buf.length) { + throw new ParseException(String.format("Insufficient data for LLVAR field, pos %d", pos), pos); + } + String _v = length == 0 ? "" : new String(buf, pos + 2, length); + if (custom == null) { + return new IsoValue(type, _v, length, null); + } else { + IsoValue v = new IsoValue(type, custom.decodeField(_v), length, custom); + if (v.getValue() == null) { + return new IsoValue(type, _v, length, null); + } + return v; + } + } + + public IsoValue parseBinary(byte[] buf, int pos, CustomField custom) throws ParseException { + + length = (((buf[pos] & 0xf0) >> 4) * 10) + (buf[pos] & 0x0f); + if (length < 0) { + throw new ParseException(String.format("Invalid LLVAR length %d pos %d", length, pos), pos); + } + if (pos+1 > buf.length || length+pos+1 > buf.length) { + throw new ParseException(String.format("Insufficient data for LLVAR field, pos %d", pos), pos); + } + if (custom == null) { + return new IsoValue(type, new String(buf, pos + 1, length), null); + } else { + IsoValue v = new IsoValue(type, custom.decodeField(new String(buf, pos + 1, length)), custom); + if (v.getValue() == null) { + return new IsoValue(type, new String(buf, pos + 1, length), null); + } + return v; + } + } + +} diff --git a/src/main/java/com/solab/iso8583/parse/NumericParseInfo.java b/src/main/java/com/solab/iso8583/parse/NumericParseInfo.java new file mode 100644 index 0000000..1e93ae5 --- /dev/null +++ b/src/main/java/com/solab/iso8583/parse/NumericParseInfo.java @@ -0,0 +1,44 @@ +package com.solab.iso8583.parse; + +import java.math.BigInteger; +import java.text.ParseException; + +import com.solab.iso8583.CustomField; +import com.solab.iso8583.IsoType; +import com.solab.iso8583.IsoValue; + +/** This class is used to parse NUMERIC fields. + * + * @author Enrique Zamudio + */ +public class NumericParseInfo extends AlphaNumericFieldParseInfo { + + public NumericParseInfo(int len) { + super(IsoType.NUMERIC, len); + } + + public IsoValue parseBinary(byte[] buf, int pos, CustomField custom) throws ParseException { + //A long covers up to 18 digits + if (length < 19) { + long l = 0; + long power = 1L; + for (int i = pos + (length / 2) + (length % 2) - 1; i >= pos; i--) { + l += (buf[i] & 0x0f) * power; + power *= 10L; + l += ((buf[i] & 0xf0) >> 4) * power; + power *= 10L; + } + return new IsoValue(IsoType.NUMERIC, l, length, null); + } else { + //Use a BigInteger + char[] digits = new char[length]; + int start = 0; + for (int i = pos; i < pos + (length / 2) + (length % 2); i++) { + digits[start++] = (char)(((buf[i] & 0xf0) >> 4) + 48); + digits[start++] = (char)((buf[i] & 0x0f) + 48); + } + return new IsoValue(IsoType.NUMERIC, new BigInteger(new String(digits)), length, null); + } + } + +} diff --git a/src/main/java/com/solab/iso8583/parse/TimeParseInfo.java b/src/main/java/com/solab/iso8583/parse/TimeParseInfo.java new file mode 100644 index 0000000..5ae2a87 --- /dev/null +++ b/src/main/java/com/solab/iso8583/parse/TimeParseInfo.java @@ -0,0 +1,52 @@ +package com.solab.iso8583.parse; + +import java.text.ParseException; +import java.util.Calendar; +import java.util.Date; + +import com.solab.iso8583.CustomField; +import com.solab.iso8583.IsoType; +import com.solab.iso8583.IsoValue; + +/** This class is used to parse TIME fields. + * + * @author Enrique Zamudio + */ +public class TimeParseInfo extends FieldParseInfo { + + + public TimeParseInfo() { + super(IsoType.TIME, 6); + } + + @Override + public IsoValue parse(byte[] buf, int pos, CustomField custom) + throws ParseException { + if (pos < 0) { + throw new ParseException(String.format("Invalid position %d", pos), pos); + } + if (pos+6 > buf.length) { + throw new ParseException(String.format("Insufficient data for TIME field, pos %d", pos), pos); + } + Calendar cal = Calendar.getInstance(); + cal.set(Calendar.HOUR_OF_DAY, ((buf[pos] - 48) * 10) + buf[pos + 1] - 48); + cal.set(Calendar.MINUTE, ((buf[pos + 2] - 48) * 10) + buf[pos + 3] - 48); + cal.set(Calendar.SECOND, ((buf[pos + 4] - 48) * 10) + buf[pos + 5] - 48); + return new IsoValue(type, cal.getTime(), null); + } + + @Override + public IsoValue parseBinary(byte[] buf, int pos, CustomField custom) throws ParseException { + int[] tens = new int[3]; + int start = 0; + for (int i = pos; i < pos + tens.length; i++) { + tens[start++] = (((buf[i] & 0xf0) >> 4) * 10) + (buf[i] & 0x0f); + } + Calendar cal = Calendar.getInstance(); + cal.set(Calendar.HOUR_OF_DAY, tens[0]); + cal.set(Calendar.MINUTE, tens[1]); + cal.set(Calendar.SECOND, tens[2]); + return new IsoValue(type, cal.getTime(), null); + } + +}