PageRenderTime 45ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 0ms

/src/main/java/com/solab/iso8583/util/Bcd.java

https://bitbucket.org/chochos/j8583
Java | 170 lines | 110 code | 11 blank | 49 comment | 19 complexity | e5c17d2e29c06cf9adb254235d6332f9 MD5 | raw file
  1. /*
  2. * j8583 A Java implementation of the ISO8583 protocol
  3. * Copyright (C) 2007 Enrique Zamudio Lopez
  4. *
  5. * This library is free software; you can redistribute it and/or
  6. * modify it under the terms of the GNU Lesser General Public
  7. * License as published by the Free Software Foundation; either
  8. * version 3 of the License, or (at your option) any later version.
  9. *
  10. * This library is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  13. * Lesser General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU Lesser General Public
  16. * License along with this library; if not, write to the Free Software
  17. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
  18. */
  19. package com.solab.iso8583.util;
  20. import java.math.BigInteger;
  21. import java.text.ParseException;
  22. /**
  23. * Routines for Binary Coded Digits.
  24. *
  25. * @author Enrique Zamudio
  26. * Date: 23/04/13 11:24
  27. */
  28. public final class Bcd {
  29. private Bcd(){}
  30. /** Decodes a BCD-encoded number as a long.
  31. * @param buf The byte buffer containing the BCD data.
  32. * @param pos The starting position in the buffer.
  33. * @param length The number of DIGITS (not bytes) to read. */
  34. public static long decodeToLong(byte[] buf, int pos, int length)
  35. throws IndexOutOfBoundsException {
  36. if (length > 18) {
  37. throw new IndexOutOfBoundsException("Buffer too big to decode as long");
  38. }
  39. long l = 0;
  40. long power = 1L;
  41. for (int i = pos + (length / 2) + (length % 2) - 1; i >= pos; i--) {
  42. l += (buf[i] & 0x0f) * power;
  43. power *= 10L;
  44. l += ((buf[i] & 0xf0) >> 4) * power;
  45. power *= 10L;
  46. }
  47. return l;
  48. }
  49. public static long decodeRightPaddedToLong(byte[] buf, int pos, int length)
  50. throws IndexOutOfBoundsException {
  51. if (length > 18) {
  52. throw new IndexOutOfBoundsException("Buffer too big to decode as long");
  53. }
  54. long l = 0;
  55. long power = 1L;
  56. int end = pos + (length / 2) + (length % 2) - 1;
  57. if ((buf[end] & 0xf) == 0xf) {
  58. l += (buf[end] & 0xf0) >> 4;
  59. power *= 10L;
  60. end--;
  61. }
  62. for (int i = end; i >= pos; i--) {
  63. l += (buf[i] & 0x0f) * power;
  64. power *= 10L;
  65. l += ((buf[i] & 0xf0) >> 4) * power;
  66. power *= 10L;
  67. }
  68. return l;
  69. }
  70. /** Encode the value as BCD and put it in the buffer. The buffer must be big enough
  71. * to store the digits in the original value (half the length of the string). */
  72. public static void encode(String value, byte[] buf) {
  73. int charpos = 0; //char where we start
  74. int bufpos = 0;
  75. if (value.length() % 2 == 1) {
  76. //for odd lengths we encode just the first digit in the first byte
  77. buf[0] = (byte)(value.charAt(0) - 48);
  78. charpos = 1;
  79. bufpos = 1;
  80. }
  81. //encode the rest of the string
  82. while (charpos < value.length()) {
  83. buf[bufpos] = (byte)(((value.charAt(charpos) - 48) << 4)
  84. | (value.charAt(charpos + 1) - 48));
  85. charpos += 2;
  86. bufpos++;
  87. }
  88. }
  89. /** Encode the value as BCD and put it in the buffer. The buffer must be big enough
  90. * to store the digits in the original value (half the length of the string).
  91. * If the value contains an odd number of digits, the last one is stored in
  92. * its own byte at the end, padded with an F nibble. */
  93. public static void encodeRightPadded(String value, byte[] buf) {
  94. int bufpos = 0;
  95. int charpos = 0;
  96. int limit = value.length();
  97. if (limit % 2 == 1) {
  98. limit--;
  99. }
  100. //encode the rest of the string
  101. while (charpos < limit) {
  102. buf[bufpos] = (byte)(((value.charAt(charpos) - 48) << 4)
  103. | (value.charAt(charpos + 1) - 48));
  104. charpos += 2;
  105. bufpos++;
  106. }
  107. if (value.length() % 2 == 1) {
  108. buf[bufpos] = (byte)(((value.charAt(limit) - 48) << 4)
  109. | 0xf);
  110. }
  111. }
  112. /** Decodes a BCD-encoded number as a BigInteger.
  113. * @param buf The byte buffer containing the BCD data.
  114. * @param pos The starting position in the buffer.
  115. * @param length The number of DIGITS (not bytes) to read. */
  116. public static BigInteger decodeToBigInteger(byte[] buf, int pos, int length)
  117. throws IndexOutOfBoundsException {
  118. char[] digits = new char[length];
  119. int start = 0;
  120. int i = pos;
  121. if (length % 2 != 0) {
  122. digits[start++] = (char)((buf[i] & 0x0f) + 48);
  123. i++;
  124. }
  125. for (;i < pos + (length / 2) + (length % 2); i++) {
  126. digits[start++] = (char)(((buf[i] & 0xf0) >> 4) + 48);
  127. digits[start++] = (char)((buf[i] & 0x0f) + 48);
  128. }
  129. return new BigInteger(new String(digits));
  130. }
  131. /** Decodes a right-padded BCD-encoded number as a BigInteger.
  132. * @param buf The byte buffer containing the BCD data.
  133. * @param pos The starting position in the buffer.
  134. * @param length The number of DIGITS (not bytes) to read. */
  135. public static BigInteger decodeRightPaddedToBigInteger(byte[] buf, int pos, int length)
  136. throws IndexOutOfBoundsException {
  137. char[] digits = new char[length];
  138. int start = 0;
  139. int i = pos;
  140. int limit = pos + (length / 2) + (length % 2);
  141. for (;i < limit; i++) {
  142. digits[start++] = (char)(((buf[i] & 0xf0) >> 4) + 48);
  143. int r = buf[i] & 0xf;
  144. digits[start++] = r == 15 ? ' ' : (char)(r + 48);
  145. }
  146. return new BigInteger(new String(digits, 0, start).trim());
  147. }
  148. /** Convert two bytes of BCD length to an int,
  149. * e.g. 0x4521 into 4521, starting at the specified offset. */
  150. public static int parseBcdLength(byte b) {
  151. return (((b & 0xf0) >> 4) * 10) + (b & 0xf);
  152. }
  153. /** Convert two bytes of BCD length to an int,
  154. * e.g. 0x4521 into 4521, starting at the specified offset. */
  155. public static int parseBcdLength2bytes(byte[] b, int offset) {
  156. return (((b[offset] & 0xf0) >> 4) * 1000) + ((b[offset] & 0xf) * 100) +
  157. (((b[offset + 1] & 0xf0) >> 4) * 10) + (b[offset + 1] & 0xf);
  158. }
  159. }