Skip to content

Commit

Permalink
Allow nonnumeric strings at end of proc arrays (oshi#1073)
Browse files Browse the repository at this point in the history
* Allow nonnumeric strings at end of proc arrays

* Handle long values above max
  • Loading branch information
dbwiddis authored Jan 1, 2020
1 parent 7d4894b commit e6d8a5c
Show file tree
Hide file tree
Showing 2 changed files with 73 additions and 17 deletions.
70 changes: 55 additions & 15 deletions oshi-core/src/main/java/oshi/util/ParseUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -661,6 +661,10 @@ public static String removeMatchingString(final String original, final String to
* sys filesystem, minimizing new object creation. Users should perform other
* sanity checks of data.
*
* As a special case, non-numeric fields (such as UUIDs in OpenVZ) at the end of
* the list are ignored. Values greater than the max long value return the max
* long value.
*
* The indices parameters are referenced assuming the length as specified, and
* leading characters are ignored. For example, if the string is "foo 12 34 5"
* and the length is 3, then index 0 is 12, index 1 is 34, and index 2 is 5.
Expand Down Expand Up @@ -693,33 +697,50 @@ public static long[] parseStringToLongArray(String s, int[] indices, int length,
int power = 0;
int c;
boolean delimCurrent = false;
boolean numeric = true;
boolean numberFound = false; // ignore nonnumeric at end
boolean dashSeen = false; // to flag uuids as nonnumeric
while (--charIndex > 0 && parsedIndex >= 0) {
c = s.charAt(charIndex);
if (c == delimiter) {
// first parseable number?
if (!numberFound && numeric) {
numberFound = true;
}
if (!delimCurrent) {
power = 0;
if (indices[parsedIndex] == stringIndex--) {
parsedIndex--;
if (numberFound) {
if (indices[parsedIndex] == stringIndex--) {
parsedIndex--;
}
}
delimCurrent = true;
power = 0;
dashSeen = false;
numeric = true;
}
} else if (indices[parsedIndex] != stringIndex || c == '+') {
} else if (indices[parsedIndex] != stringIndex || c == '+' || !numeric) {
// Doesn't impact parsing, ignore
delimCurrent = false;
} else if (c >= '0' && c <= '9') {
if (power > 18) {
LOG.error("Number is too big for a long parsing string '{}' to long array", s);
return new long[indices.length];
} else if (c >= '0' && c <= '9' && !dashSeen) {
if (power > 18 || power == 17 && c == '9' && parsed[parsedIndex] > 223372036854775807L) {
parsed[parsedIndex] = Long.MAX_VALUE;
} else {
parsed[parsedIndex] += (c - '0') * ParseUtil.POWERS_OF_TEN[power++];
}
parsed[parsedIndex] += (c - '0') * ParseUtil.POWERS_OF_TEN[power++];
delimCurrent = false;
} else if (c == '-') {
parsed[parsedIndex] *= -1L;
delimCurrent = false;
dashSeen = true;
} else {
// Flag as nonnumeric and continue unless we've seen a numeric
// error on everything else
LOG.error("Illegal character parsing string '{}' to long array: {}", s, s.charAt(charIndex));
return new long[indices.length];
if (numberFound) {
LOG.error("Illegal character parsing string '{}' to long array: {}", s, s.charAt(charIndex));
return new long[indices.length];
}
parsed[parsedIndex] = 0;
numeric = false;
}
}
if (parsedIndex > 0) {
Expand All @@ -734,6 +755,9 @@ public static long[] parseStringToLongArray(String s, int[] indices, int length,
* be called once to calculate the {@code length} field for
* {@link #parseStringToLongArray}.
*
* As a special case, non-numeric fields (such as UUIDs in OpenVZ) at the end of
* the list are ignored.
*
* @param s
* The string to parse
* @param delimiter
Expand All @@ -749,18 +773,34 @@ public static int countStringToLongArray(String s, char delimiter) {

int c;
boolean delimCurrent = false;
boolean numeric = true;
boolean dashSeen = false; // to flag uuids as nonnumeric
while (--charIndex > 0) {
c = s.charAt(charIndex);
if (c == delimiter) {
if (!delimCurrent) {
numbers++;
if (numeric) {
numbers++;
}
delimCurrent = true;
dashSeen = false;
numeric = true;
}
} else if (c >= '0' && c <= '9' || c == '-' || c == '+') {
} else if (c == '+' || !numeric) {
// Doesn't impact parsing, ignore
delimCurrent = false;
} else if (c >= '0' && c <= '9' && !dashSeen) {
delimCurrent = false;
} else if (c == '-') {
delimCurrent = false;
dashSeen = true;
} else {
// we found non-digit or delimiter, exit
return numbers;
// we found non-digit or delimiter. If not last field, exit
if (numbers > 0) {
return numbers;
}
// Else flag as nonnumeric and continue
numeric = false;
}
}
// We got to beginning of string with only numbers, count start as a delimiter
Expand Down
20 changes: 18 additions & 2 deletions oshi-core/src/test/java/oshi/util/ParseUtilTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -326,6 +326,14 @@ public void testParseStringToLongArray() {
assertEquals(456L, result[0]);
assertEquals(now, result[1]);

foo = String.format("The numbers are %d %d %d %d %s", 123, 456, 789, now,
"709af748-5f8e-41b3-b73a-b440ef4406c8");
count = ParseUtil.countStringToLongArray(foo, ' ');
assertEquals(4, count);
result = ParseUtil.parseStringToLongArray(foo, indices, 4, ' ');
assertEquals(456L, result[0]);
assertEquals(now, result[1]);

foo = String.format("The numbers are %d -%d %d +%d", 123, 456, 789, now);
count = ParseUtil.countStringToLongArray(foo, ' ');
assertEquals(4, count);
Expand All @@ -339,9 +347,9 @@ public void testParseStringToLongArray() {
result = ParseUtil.parseStringToLongArray(foo, indices, 4, ' ');
assertEquals(0, result[1]);

foo = String.format("Exceeds max long %d %d %d %d0", 123, 456, 789, Long.MAX_VALUE);
foo = String.format("Exceeds max long %d %d %d 1%d", 123, 456, 789, Long.MAX_VALUE);
result = ParseUtil.parseStringToLongArray(foo, indices, 4, ' ');
assertEquals(0, result[1]);
assertEquals(Long.MAX_VALUE, result[1]);

foo = String.format("String too short %d %d %d %d", 123, 456, 789, now);
result = ParseUtil.parseStringToLongArray(foo, indices, 9, ' ');
Expand All @@ -354,6 +362,14 @@ public void testParseStringToLongArray() {
foo = String.format("%d %d %d %d", 123, 456, 789, now);
count = ParseUtil.countStringToLongArray(foo, ' ');
assertEquals(4, count);

foo = String.format("%d %d %d %d nonNumeric", 123, 456, 789, now);
count = ParseUtil.countStringToLongArray(foo, ' ');
assertEquals(4, count);

foo = String.format("%d %d %d %d 123-456", 123, 456, 789, now);
count = ParseUtil.countStringToLongArray(foo, ' ');
assertEquals(4, count);
}

@Test
Expand Down

0 comments on commit e6d8a5c

Please sign in to comment.