2020package quickfix .field .converter ;
2121
2222import quickfix .FieldConvertError ;
23+ import quickfix .NumbersCache ;
2324
2425/**
2526 * Convert between an integer and a String
2627 */
2728public final class IntConverter {
2829
30+ private static final String INT_MAX_STRING = String .valueOf (Integer .MAX_VALUE );
31+
2932 /**
3033 * Convert an integer to a String
3134 *
3235 * @param i the integer to convert
3336 * @return the String representing the integer
34- * @see java.lang.Long#toString(long)
37+ * @see NumbersCache#get(int)
3538 */
3639 public static String convert (int i ) {
37- return Long . toString (i );
40+ return NumbersCache . get (i );
3841 }
3942
4043 /**
@@ -43,22 +46,68 @@ public static String convert(int i) {
4346 * @param value the String to convert
4447 * @return the converted integer
4548 * @throws FieldConvertError raised if the String does not represent a valid
46- * integer
49+ * FIX integer, i.e. optional negative sign and rest are digits.
4750 * @see java.lang.Integer#parseInt(String)
4851 */
4952 public static int convert (String value ) throws FieldConvertError {
50- try {
51- for (int i = 0 ; i < value .length (); i ++) {
52- if (!Character .isDigit (value .charAt (i )) && !(i == 0 && value .charAt (i ) == '-' )) {
53- throw new FieldConvertError ("invalid integral value: " + value );
53+
54+ if (!value .isEmpty ()) {
55+ final char firstChar = value .charAt (0 );
56+ boolean isNegative = (firstChar == '-' );
57+ if (!isDigit (firstChar ) && !isNegative ) {
58+ throw new FieldConvertError ("invalid integral value: " + value );
59+ }
60+ int minLength = (isNegative ? 2 : 1 );
61+ if (value .length () < minLength ) {
62+ throw new FieldConvertError ("invalid integral value: " + value );
63+ }
64+
65+ // Heuristic: since we have no range check in our parseInt() we only parse
66+ // values which have at least one digit less than Integer.MAX_VALUE and
67+ // leave longer Strings to Integer.parseInt().
68+ // NB: we must not simply reject strings longer than MAX_VALUE since
69+ // they could possibly include an arbitrary number of leading zeros.
70+ int maxLength = (isNegative ? INT_MAX_STRING .length () : INT_MAX_STRING .length () - 1 );
71+ if (value .length () <= maxLength ) {
72+ return parseInt (value , isNegative );
73+ } else {
74+ try {
75+ return Integer .parseInt (value );
76+ } catch (NumberFormatException e ) {
77+ throw new FieldConvertError ("invalid integral value: " + value + ": " + e );
5478 }
5579 }
56- return Integer .parseInt (value );
57- } catch (NumberFormatException e ) {
58- throw new FieldConvertError ("invalid integral value: " + value + ": " + e );
80+ } else {
81+ throw new FieldConvertError ("invalid integral value: empty string" );
5982 }
6083 }
6184
85+ /**
86+ * Please note that input needs to be validated first, otherwise unexpected
87+ * results may occur. Please also note that this method has no range or
88+ * overflow check, so please only use it when you are sure that no overflow
89+ * might occur (e.g. for parsing seconds or smaller integers).
90+ *
91+ * This method does however check if the contained characters are digits.
92+ *
93+ * @param value the String to convert
94+ * @param isNegative if passed String is negative, first character will
95+ * be skipped since it is assumed that it contains the negative sign
96+ * @return the converted int
97+ */
98+ private static int parseInt (String value , boolean isNegative ) throws FieldConvertError {
99+ int num = 0 ;
100+ int firstIndex = (isNegative ? 1 : 0 );
101+ for (int i = firstIndex ; i < value .length (); i ++) {
102+ if (isDigit (value .charAt (i ))) {
103+ num = (num * 10 ) + (value .charAt (i ) - '0' );
104+ } else {
105+ throw new FieldConvertError ("invalid integral value: " + value );
106+ }
107+ }
108+ return isNegative ? -num : num ;
109+ }
110+
62111 /**
63112 * Please note that input needs to be validated first, otherwise unexpected
64113 * results may occur. Please also note that this method has no range or overflow
@@ -106,4 +155,15 @@ static long parseLong(String value) {
106155 }
107156 return negative ? -num : num ;
108157 }
158+
159+ /**
160+ * Check if a character is a digit, i.e. in the range between 0 and 9.
161+ *
162+ * @param character character to check
163+ * @return true if character is a digit between 0 and 9
164+ */
165+ static boolean isDigit (char character ) {
166+ return (character >= '0' && character <= '9' );
167+ }
168+
109169}
0 commit comments