Skip to content
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -226,8 +226,11 @@ static SchemaTypeSystemImpl compileImpl(SchemaTypeSystem system, String name,
// load all the xsd files into it
if (validate) {
XmlOptions validateOptions = new XmlOptions().setErrorListener(errorWatcher);
if (options != null && options.isValidateTreatLaxAsSkip()) {
validateOptions.setValidateTreatLaxAsSkip();
if (options != null) {
if (options.isValidateTreatLaxAsSkip()) {
validateOptions.setValidateTreatLaxAsSkip();
}
validateOptions.setMaxNumberOfCharsForNumbers(options.getMaxNumberOfCharsForNumbers());
}
for (Schema schema : schemas) {
if (schema.validate(validateOptions)) {
Expand Down
10 changes: 10 additions & 0 deletions src/main/java/org/apache/xmlbeans/impl/schema/StscState.java
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ public class StscState {
private boolean _noAnn;
private boolean _mdefAll;
private String _sourceCodeEncoding ;
private int _maxNumberOfCharsForNumbers = XmlOptions.DEFAULT_MAX_NUMBER_CHARS;
private final Set<String> _mdefNamespaces = buildDefaultMdefNamespaces();
private EntityResolver _entityResolver;
private File _schemasDir;
Expand Down Expand Up @@ -462,6 +463,7 @@ public void setOptions(XmlOptions options) {
!"true".equals(SystemProperties.getProperty("xmlbean.schemaannotations", "true"));
_doingDownloads = options.isCompileDownloadUrls() ||
"true".equals(SystemProperties.getProperty("xmlbean.downloadurls", "false"));
_maxNumberOfCharsForNumbers = options.getMaxNumberOfCharsForNumbers();
_sourceCodeEncoding = options.getCharacterEncoding();
if (_sourceCodeEncoding == null || _sourceCodeEncoding.isEmpty()) {
_sourceCodeEncoding = SystemProperties.getProperty("xmlbean.sourcecodeencoding");
Expand Down Expand Up @@ -538,6 +540,14 @@ public String sourceCodeEncoding() {
return _sourceCodeEncoding ;
}

/**
* The maximum number of characters a number in the schema being compiled may have,
* as configured by XmlOptions.setMaxNumberOfCharsForNumbers.
*/
public int maxNumberOfCharsForNumbers() {
return _maxNumberOfCharsForNumbers;
}

/**
* Get count of recovered errors. Not for public.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1509,10 +1509,13 @@ static BigInteger buildBigInt(XmlAnySimpleType value) {
if (value == null) {
return null;
}
String text = value.getStringValue();
// materialising the facet's text can fail in its own right, if the schema was
// loaded with a lower limit than the number it declares, so it is inside the try
String text = null;
BigInteger bigInt;
try {
bigInt = MathUtil.parseAsBigInteger(text);
text = value.getStringValue();
bigInt = MathUtil.parseAsBigInteger(text, StscState.get().maxNumberOfCharsForNumbers());
} catch (Exception e) {
StscState.get().error(XmlErrorCodes.INVALID_VALUE_DETAIL, new Object[]{text, "nonNegativeInteger", e.getMessage()}, value);
return null;
Expand Down
16 changes: 14 additions & 2 deletions src/main/java/org/apache/xmlbeans/impl/validator/Validator.java
Original file line number Diff line number Diff line change
Expand Up @@ -1110,8 +1110,20 @@ private void validateAtomicType(
}

if (errorState == _errorState) {
_decimalValue = MathUtil.parseAsBigDecimal(value, _options.getMaxNumberOfCharsForNumbers());
JavaDecimalHolderEx.validateValue(_decimalValue, type, _vc);
BigDecimal parsed = null;
try {
parsed = MathUtil.parseAsBigDecimal(value, _options.getMaxNumberOfCharsForNumbers());
} catch (IllegalArgumentException e) {
// a number longer than the configured maximum is invalid input,
// not a programming error - report it like any other bad value
// rather than throwing out of validate()
_vc.invalid(derivedFromInteger(type) ? XmlErrorCodes.INTEGER : XmlErrorCodes.DECIMAL,
new Object[]{value});
}
if (parsed != null) {
_decimalValue = parsed;
JavaDecimalHolderEx.validateValue(_decimalValue, type, _vc);
}
}

break;
Expand Down
48 changes: 48 additions & 0 deletions src/test/java/misc/checkin/MaxNumberOfCharsTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,22 +14,30 @@
*/
package misc.checkin;

import org.apache.xmlbeans.SchemaTypeSystem;
import org.apache.xmlbeans.SimpleValue;
import org.apache.xmlbeans.XmlBeans;
import org.apache.xmlbeans.XmlDecimal;
import org.apache.xmlbeans.XmlError;
import org.apache.xmlbeans.XmlException;
import org.apache.xmlbeans.XmlInt;
import org.apache.xmlbeans.XmlInteger;
import org.apache.xmlbeans.XmlLong;
import org.apache.xmlbeans.XmlObject;
import org.apache.xmlbeans.XmlOptions;
import org.apache.xmlbeans.impl.values.XmlValueOutOfRangeException;
import org.junit.jupiter.api.Test;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.List;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTimeoutPreemptively;
import static org.junit.jupiter.api.Assertions.assertTrue;

/**
* XmlOptions.setMaxNumberOfCharsForNumbers has to apply to values materialised from the
Expand Down Expand Up @@ -214,6 +222,46 @@ public void testDecimalStillAcceptsExponentWithinLimit() throws XmlException {
assertEquals(2001, wide.getBigDecimalValue().precision() - wide.getBigDecimalValue().scale());
}

@Test
public void testValidateReportsAnOverLongNumber() throws XmlException {
// validate() reports what is wrong with a document; a number past the limit is
// bad input like any other and must not come back as an exception
List<XmlError> errors = new ArrayList<>();
XmlInteger integer = XmlInteger.Factory.parse(frag(digits(2000)));
assertFalse(integer.validate(new XmlOptions().setErrorListener(errors)));
assertFalse(errors.isEmpty());

errors.clear();
XmlDecimal decimal = XmlDecimal.Factory.parse(frag(digits(2000) + ".5"));
assertFalse(decimal.validate(new XmlOptions().setErrorListener(errors)));
assertFalse(errors.isEmpty());
}

@Test
public void testSchemaCompileHonoursLimit() throws XmlException {
// the facet value is a number in the schema document, so the limit has to reach
// the validation and the facet handling that compilation does
String xsd = "<xs:schema xmlns:xs='http://www.w3.org/2001/XMLSchema'>" +
"<xs:element name='value' type='boundedString'/>" +
"<xs:simpleType name='boundedString'><xs:restriction base='xs:string'>" +
"<xs:maxLength value='" + digits(2000) + "'/>" +
"</xs:restriction></xs:simpleType></xs:schema>";

XmlOptions raised = maxChars(4096);
SchemaTypeSystem sts = XmlBeans.compileXsd(
new XmlObject[]{XmlObject.Factory.parse(xsd, raised)}, XmlBeans.getBuiltinTypeSystem(), raised);
assertEquals(1, sts.globalElements().length);

// at the default limit the same schema is reported as invalid, not thrown out of
List<XmlError> errors = new ArrayList<>();
XmlOptions dflt = new XmlOptions().setErrorListener(errors);
XmlObject parsed = XmlObject.Factory.parse(xsd);
assertThrows(XmlException.class,
() -> XmlBeans.compileXsd(new XmlObject[]{parsed}, XmlBeans.getBuiltinTypeSystem(), dflt));
assertTrue(errors.stream().anyMatch(e -> e.getMessage().contains("Invalid integer value")),
errors.toString());
}

@Test
public void testDecimalHashCodeIgnoresLimit() {
// hashCode() must not throw, whatever the limit is, and must stay aligned with
Expand Down
Loading