diff --git a/src/main/java/com/solab/iso8583/IsoValue.java b/src/main/java/com/solab/iso8583/IsoValue.java index 7ea05e7..8ebc77c 100644 --- a/src/main/java/com/solab/iso8583/IsoValue.java +++ b/src/main/java/com/solab/iso8583/IsoValue.java @@ -23,6 +23,7 @@ import java.io.OutputStream; import java.math.BigDecimal; import java.util.Date; +import com.solab.iso8583.util.Bcd; import com.solab.iso8583.util.HexCodec; /** Represents a value that is stored in a field inside an ISO8583 message. @@ -291,7 +292,7 @@ public class IsoValue implements Cloneable { } //Encode in BCD if it's one of these types if (buf != null) { - toBcd(toString(), buf); + Bcd.encode(toString(), buf); outs.write(buf); return; } @@ -316,24 +317,4 @@ public class IsoValue implements Cloneable { } } - /** Encode the value as BCD and put it in the buffer. The buffer must be big enough - * to store the digits in the original value (half the length of the string). */ - private void toBcd(String value, byte[] buf) { - int charpos = 0; //char where we start - int bufpos = 0; - if (value.length() % 2 == 1) { - //for odd lengths we encode just the first digit in the first byte - buf[0] = (byte)(value.charAt(0) - 48); - charpos = 1; - bufpos = 1; - } - //encode the rest of the string - while (charpos < value.length()) { - buf[bufpos] = (byte)(((value.charAt(charpos) - 48) << 4) - | (value.charAt(charpos + 1) - 48)); - charpos += 2; - bufpos++; - } - } - } diff --git a/src/main/java/com/solab/iso8583/parse/NumericParseInfo.java b/src/main/java/com/solab/iso8583/parse/NumericParseInfo.java index d0f8904..c33ef53 100644 --- a/src/main/java/com/solab/iso8583/parse/NumericParseInfo.java +++ b/src/main/java/com/solab/iso8583/parse/NumericParseInfo.java @@ -24,6 +24,7 @@ import java.text.ParseException; import com.solab.iso8583.CustomField; import com.solab.iso8583.IsoType; import com.solab.iso8583.IsoValue; +import com.solab.iso8583.util.Bcd; /** This class is used to parse NUMERIC fields. * @@ -49,30 +50,18 @@ public class NumericParseInfo extends AlphaNumericFieldParseInfo { } //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); + return new IsoValue(IsoType.NUMERIC, Bcd.decodeToLong(buf, pos, length), + length, null); } else { //Use a BigInteger - char[] digits = new char[length]; - int start = 0; try { - 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, + Bcd.decodeToBigInteger(buf, pos, length), length, null); } catch (IndexOutOfBoundsException ex) { throw new ParseException(String.format( - "Insufficient data for bin %s field %d of length %d, pos %d", - type, field, length, pos), pos); + "Insufficient data for bin %s field %d of length %d, pos %d", + type, field, length, pos), pos); } - return new IsoValue(IsoType.NUMERIC, new BigInteger(new String(digits)), length, null); } } diff --git a/src/main/java/com/solab/iso8583/util/Bcd.java b/src/main/java/com/solab/iso8583/util/Bcd.java new file mode 100644 index 0000000..39957d0 --- /dev/null +++ b/src/main/java/com/solab/iso8583/util/Bcd.java @@ -0,0 +1,63 @@ +package com.solab.iso8583.util; + +import java.math.BigInteger; +import java.text.ParseException; + +/** + * Routines for Binary Coded Digits. + * + * @author Enrique Zamudio + * Date: 23/04/13 11:24 + */ +public final class Bcd { + + private Bcd(){} + + public static long decodeToLong(byte[] buf, int pos, int length) + throws IndexOutOfBoundsException { + if (length > 18) { + throw new IndexOutOfBoundsException("Buffer too big to decode as long"); + } + 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 l; + } + + /** Encode the value as BCD and put it in the buffer. The buffer must be big enough + * to store the digits in the original value (half the length of the string). */ + public static void encode(String value, byte[] buf) { + int charpos = 0; //char where we start + int bufpos = 0; + if (value.length() % 2 == 1) { + //for odd lengths we encode just the first digit in the first byte + buf[0] = (byte)(value.charAt(0) - 48); + charpos = 1; + bufpos = 1; + } + //encode the rest of the string + while (charpos < value.length()) { + buf[bufpos] = (byte)(((value.charAt(charpos) - 48) << 4) + | (value.charAt(charpos + 1) - 48)); + charpos += 2; + bufpos++; + } + } + + public static BigInteger decodeToBigInteger(byte[] buf, int pos, int length) + throws IndexOutOfBoundsException { + 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 BigInteger(new String(digits)); + } + +}