Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 26 additions & 18 deletions src/main/java/org/apache/xmlbeans/impl/util/XsTypeConverter.java
Original file line number Diff line number Diff line change
Expand Up @@ -275,11 +275,7 @@ public static String printDecimal(BigDecimal value) {
// ======================== integer ========================
public static BigInteger lexInteger(CharSequence cs)
throws NumberFormatException {
if (cs.length() > 1) {
if (cs.charAt(0) == '+' && cs.charAt(1) == '-') {
throw new NumberFormatException("Illegal char sequence '+-'");
}
}
rejectSignAfterPlus(cs);
final String v = cs.toString();

//TODO: consider special casing zero and one to return static values
Expand All @@ -304,10 +300,25 @@ public static String printInteger(BigInteger value) {
// ======================== long ========================
public static long lexLong(CharSequence cs)
throws NumberFormatException {
rejectSignAfterPlus(cs);
final String v = cs.toString();
return Long.parseLong(trimInitialPlus(v));
}

// trimInitialPlus drops a single leading '+', then Long.parseLong /
// new BigInteger accept their own leading sign, so "++5" and "+-5" slip
// through as 5 and -5. Neither is in the xsd integer lexical space
// ([\-+]?[0-9]+ allows one sign). lexInt/lexShort/lexByte already reject
// the second sign in parseIntXsdNumber.
private static void rejectSignAfterPlus(CharSequence cs) {
if (cs.length() > 1 && cs.charAt(0) == '+') {
final char c = cs.charAt(1);
if (c == '+' || c == '-') {
throw new NumberFormatException("Illegal char sequence '+" + c + "'");
}
}
}

public static long lexLong(CharSequence cs, Collection<XmlError> errors) {
try {
return lexLong(cs);
Expand Down Expand Up @@ -432,7 +443,7 @@ public static boolean lexBoolean(CharSequence value, Collection<XmlError> errors
}

public static String printBoolean(boolean value) {
return (value ? "true" : "false");
return Boolean.toString(value);
}


Expand Down Expand Up @@ -469,7 +480,7 @@ public static QName lexQName(CharSequence charSeq, NamespaceContext nscontext) {
String uri = nscontext.getNamespaceURI(prefix);

if (uri == null) {
if (prefix != null && prefix.length() > 0) {
if (prefix != null && !prefix.isEmpty()) {
throw new InvalidLexicalValueException("Can't resolve prefix: " + prefix);
}

Expand All @@ -495,7 +506,7 @@ public static String printQName(QName qname, NamespaceContext nsContext,
final String uri = qname.getNamespaceURI();
assert uri != null; //qname is not allowed to have null uri values
final String prefix;
if (uri.length() > 0) {
if (!uri.isEmpty()) {
prefix = nsContext.getPrefix(uri);
if (prefix == null) {
String msg = "NamespaceContext does not provide" +
Expand All @@ -513,9 +524,9 @@ public static String getQNameString(String uri,
String localpart,
String prefix) {
if (prefix != null &&
uri != null &&
uri.length() > 0 &&
prefix.length() > 0) {
uri != null &&
!uri.isEmpty() &&
!prefix.isEmpty()) {
return (prefix + NAMESPACE_SEP + localpart);
} else {
return localpart;
Expand Down Expand Up @@ -587,29 +598,26 @@ public static GDateSpecification getGDateValue(Date d,
int builtin_type_code) {
GDateBuilder gDateBuilder = new GDateBuilder(d);
gDateBuilder.setBuiltinTypeCode(builtin_type_code);
GDate value = gDateBuilder.toGDate();
return value;
return gDateBuilder.toGDate();
}


public static GDateSpecification getGDateValue(Calendar c,
int builtin_type_code) {
GDateBuilder gDateBuilder = new GDateBuilder(c);
gDateBuilder.setBuiltinTypeCode(builtin_type_code);
GDate value = gDateBuilder.toGDate();
return value;
return gDateBuilder.toGDate();
}

public static GDateSpecification getGDateValue(CharSequence v,
int builtin_type_code) {
GDateBuilder gDateBuilder = new GDateBuilder(v);
gDateBuilder.setBuiltinTypeCode(builtin_type_code);
GDate value = gDateBuilder.toGDate();
return value;
return gDateBuilder.toGDate();
}

private static String trimInitialPlus(String xml) {
if (xml.length() > 0 && xml.charAt(0) == '+') {
if (!xml.isEmpty() && xml.charAt(0) == '+') {
return xml.substring(1);
} else {
return xml;
Expand Down
19 changes: 19 additions & 0 deletions src/test/java/misc/checkin/XsTypeConverterTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,25 @@ void loadStrictFloatingPointOptionGatesDoubleParsing() throws Exception {
XmlDouble.Factory.parse("<xml-fragment>0x1p4</xml-fragment>", strict).getDoubleValue());
}

@Test
void lexLongRejectsDoubleSign() {
// trimInitialPlus drops the leading '+', then Long.parseLong accepts its
// own sign, so "++5"/"+-5" used to parse as 5/-5 instead of being rejected.
assertEquals(5L, XsTypeConverter.lexLong("+5"));
assertEquals(-5L, XsTypeConverter.lexLong("-5"));
assertThrows(NumberFormatException.class, () -> XsTypeConverter.lexLong("++5"));
assertThrows(NumberFormatException.class, () -> XsTypeConverter.lexLong("+-5"));
}

@Test
void lexIntegerRejectsDoubleSign() {
// "+-5" was already caught; "++5" leaked through as 5.
assertEquals(java.math.BigInteger.valueOf(5), XsTypeConverter.lexInteger("+5"));
assertEquals(java.math.BigInteger.valueOf(-5), XsTypeConverter.lexInteger("-5"));
assertThrows(NumberFormatException.class, () -> XsTypeConverter.lexInteger("++5"));
assertThrows(NumberFormatException.class, () -> XsTypeConverter.lexInteger("+-5"));
}

@Test
void lexDecimalRejectsEmptyString() {
// an empty value used to read charAt(-1) in trimTrailingZeros and
Expand Down
Loading