Skip to content

Commit e86902c

Browse files
committed
[bugfix] xs:hexBinary must support both upper and lower-case [a-f] characters (XQTS: prod-OrderByClause)
1 parent e98f87b commit e86902c

File tree

4 files changed

+66
-21
lines changed

4 files changed

+66
-21
lines changed

exist-core/src/main/java/org/exist/util/io/HexOutputStream.java

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,20 @@ public class HexOutputStream extends org.apache.commons.codec.binary.Base16Outpu
3939
* Creates a HexOutputStream such that all data written is Hex-encoded to the original provided OutputStream.
4040
*
4141
* @param out the OutputStream to wrap.
42-
* @param doEncode true to encode
42+
* @param doEncode true to encode.
4343
*/
4444
public HexOutputStream(final OutputStream out, final boolean doEncode) {
45-
super(out, doEncode, true, CodecPolicy.STRICT);
45+
this(out, doEncode, true);
46+
}
47+
48+
/**
49+
* Creates a HexOutputStream such that all data written is Hex-encoded to the original provided OutputStream.
50+
*
51+
* @param out the OutputStream to wrap.
52+
* @param doEncode true to encode.
53+
* @param lowerCase true to use lower case, or false for upper case.
54+
*/
55+
public HexOutputStream(final OutputStream out, final boolean doEncode, final boolean lowerCase) {
56+
super(out, doEncode, lowerCase, CodecPolicy.STRICT);
4657
}
4758
}

exist-core/src/main/java/org/exist/xquery/value/BinaryValueFromBinaryString.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ public BinaryValueFromBinaryString(BinaryValueType binaryValueType, String value
5252
this(null, binaryValueType, value);
5353
}
5454

55-
public BinaryValueFromBinaryString(final Expression expression, BinaryValueType binaryValueType, String value) throws XPathException {
55+
public BinaryValueFromBinaryString(final Expression expression, final BinaryValueType binaryValueType, final String value) throws XPathException {
5656
super(expression, null, binaryValueType);
5757
this.value = binaryValueType.verifyAndFormatString(value);
5858
}

exist-core/src/main/java/org/exist/xquery/value/HexBinaryValueType.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,14 +31,14 @@
3131
import java.util.regex.Pattern;
3232

3333
/**
34-
* @author <a href="mailto:adam@existsolutions.com">Adam Retter</a>
34+
* @author <a href="mailto:adam@evolvedbinary.com">Adam Retter</a>
3535
*/
3636
public class HexBinaryValueType extends BinaryValueType<HexOutputStream> {
3737

3838
private final static Pattern hexPattern = Pattern.compile("[A-Fa-f0-9]*");
3939

4040
public HexBinaryValueType() {
41-
super(Type.HEX_BINARY, HexOutputStream::new);
41+
super(Type.HEX_BINARY, (outputStream, doEncode) -> new HexOutputStream(outputStream, doEncode, false));
4242
}
4343

4444
private Matcher getMatcher(final String toMatch) {

exist-core/src/test/java/org/exist/xquery/value/BinaryValueFromBinaryStringTest.java

Lines changed: 50 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,17 @@
2727
import org.apache.commons.io.output.UnsynchronizedByteArrayOutputStream;
2828
import org.exist.xquery.XPathException;
2929
import java.io.IOException;
30-
import org.junit.Test;
31-
import static org.junit.Assert.assertArrayEquals;
32-
import static org.junit.Assert.assertEquals;
30+
31+
import org.junit.jupiter.api.Test;
32+
import org.junit.jupiter.params.ParameterizedTest;
33+
import org.junit.jupiter.params.provider.ValueSource;
34+
35+
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
36+
import static org.junit.jupiter.api.Assertions.assertEquals;
3337

3438
/**
3539
*
36-
* @author <a href="mailto:adam@existsolutions.com">Adam Retter</a>
40+
* @author <a href="mailto:adam@evolvedbinary.com">Adam Retter</a>
3741
*/
3842
public class BinaryValueFromBinaryStringTest {
3943

@@ -43,38 +47,68 @@ public void getInputStream() throws XPathException, IOException {
4347
final String testData = "test data";
4448
final String base64TestData = Base64.encodeBase64String(testData.getBytes()).trim();
4549

46-
BinaryValue binaryValue = new BinaryValueFromBinaryString(new Base64BinaryValueType(), base64TestData);
47-
4850

49-
try (final InputStream is = binaryValue.getInputStream();
51+
try (final BinaryValue binaryValue = new BinaryValueFromBinaryString(new Base64BinaryValueType(), base64TestData);
52+
final InputStream is = binaryValue.getInputStream();
5053
final UnsynchronizedByteArrayOutputStream baos = new UnsynchronizedByteArrayOutputStream()) {
5154
baos.write(is);
5255
assertArrayEquals(testData.getBytes(), baos.toByteArray());
5356
}
5457
}
5558

5659
@Test
57-
public void cast_base64_to_hexBinary() throws XPathException {
60+
public void cast_base64_to_hexBinary() throws XPathException, IOException {
5861

5962
final String testData = "testdata";
6063
final String expectedResult = Hex.encodeHexString(testData.getBytes()).trim();
6164

62-
BinaryValue binaryValue = new BinaryValueFromBinaryString(new Base64BinaryValueType(), Base64.encodeBase64String(testData.getBytes()));
65+
try (final BinaryValue binaryValue = new BinaryValueFromBinaryString(new Base64BinaryValueType(), Base64.encodeBase64String(testData.getBytes()))) {
6366

64-
final AtomicValue result = binaryValue.convertTo(new HexBinaryValueType());
67+
final AtomicValue result = binaryValue.convertTo(new HexBinaryValueType());
6568

66-
assertEquals(expectedResult, result.getStringValue());
69+
assertEquals(expectedResult, result.getStringValue());
70+
}
6771
}
6872

6973
@Test
70-
public void cast_hexBinary_to_base64() throws XPathException {
74+
public void cast_hexBinary_to_base64() throws XPathException, IOException {
7175
final String testData = "testdata";
7276
final String expectedResult = Base64.encodeBase64String(testData.getBytes()).trim();
7377

74-
BinaryValue binaryValue = new BinaryValueFromBinaryString(new HexBinaryValueType(), Hex.encodeHexString(testData.getBytes()));
78+
try (final BinaryValue binaryValue = new BinaryValueFromBinaryString(new HexBinaryValueType(), Hex.encodeHexString(testData.getBytes()))) {
79+
80+
final AtomicValue result = binaryValue.convertTo(new Base64BinaryValueType());
7581

76-
final AtomicValue result = binaryValue.convertTo(new Base64BinaryValueType());
82+
assertEquals(expectedResult, result.getStringValue());
83+
}
84+
}
85+
86+
@Test
87+
public void base64StreamBinaryTo() throws XPathException, IOException {
88+
try (final BinaryValue binaryValue = new BinaryValueFromBinaryString(new Base64BinaryValueType(), "yv4=");
89+
final UnsynchronizedByteArrayOutputStream baos = new UnsynchronizedByteArrayOutputStream()) {
7790

78-
assertEquals(expectedResult, result.getStringValue());
91+
binaryValue.streamBinaryTo(baos);
92+
93+
final byte[] data = baos.toByteArray();
94+
assertEquals(2, data.length);
95+
assertEquals(0xCA, data[0] & 0xFF);
96+
assertEquals(0xFE, data[1] & 0xFF);
97+
}
98+
}
99+
100+
@ParameterizedTest
101+
@ValueSource(strings = {"CAFE", "cafe"})
102+
public void hexStreamBinaryTo(final String hexString) throws XPathException, IOException {
103+
try (final BinaryValue binaryValue = new BinaryValueFromBinaryString(new HexBinaryValueType(), hexString);
104+
final UnsynchronizedByteArrayOutputStream baos = new UnsynchronizedByteArrayOutputStream()) {
105+
106+
binaryValue.streamBinaryTo(baos);
107+
108+
final byte[] data = baos.toByteArray();
109+
assertEquals(2, data.length);
110+
assertEquals(0xCA, data[0] & 0xFF);
111+
assertEquals(0xFE, data[1] & 0xFF);
112+
}
79113
}
80-
}
114+
}

0 commit comments

Comments
 (0)