/** Helper for CAST(... AS BINARY(maxLength)). */ public static ByteString truncateOrPad(ByteString s, int maxLength) { if (s == null) { return null; } else { final int length = s.length(); if (length > maxLength) { return s.substring(0, maxLength); } else if (length < maxLength) { return s.concat(new ByteString(new byte[maxLength - length])); } else { return s; } } }
/** Returns a byte-string padded with zero bytes to make it at least a given * length, */ private static ByteString padRight(ByteString s, int length) { if (s.length() >= length) { return s; } return new ByteString(Arrays.copyOf(s.getBytes(), length)); } }
/** Returns the position at which {@code seek} first occurs in this byte * string, or -1 if it does not occur. */ public int indexOf(ByteString seek) { return indexOf(seek, 0); }
@Test public void testByteString() { final byte[] bytes = {(byte) 0xAB, (byte) 0xFF}; final ByteString byteString = new ByteString(bytes); assertEquals(2, byteString.length()); assertEquals("abff", byteString.toString()); assertEquals("abff", byteString.toString(16)); assertEquals("1010101111111111", byteString.toString(2)); final ByteString emptyByteString = new ByteString(new byte[0]); assertEquals(0, emptyByteString.length()); assertEquals("", emptyByteString.toString()); assertEquals("", emptyByteString.toString(16)); assertEquals("", emptyByteString.toString(2)); assertEquals("ff", byteString.substring(1, 2).toString()); assertEquals("abff", byteString.substring(0, 2).toString()); assertEquals("", byteString.substring(2, 2).toString()); assertSame(byteString.concat(emptyByteString), byteString); final ByteString byteString1 = new ByteString(new byte[]{(byte) 12}); assertEquals("abff0c", byteString.concat(byteString1).toString()); final ByteString byteString3 = new ByteString(bytes3); assertEquals(0, byteString.indexOf(emptyByteString)); assertEquals(-1, byteString.indexOf(byteString1)); assertEquals(1, byteString.indexOf(byteString3)); assertEquals(-1, byteString3.indexOf(byteString)); thereAndBack(emptyByteString.getBytes());
@Test public void testByteString() { final byte[] bytes = {3, 14, 15, 92, 0, 65, 35, 0}; final ByteString s = new ByteString(bytes); final ByteString s2 = new ByteString(bytes.clone()); final ByteString s3 = new ByteString(new byte[0]); final ByteString s4 = new ByteString(new byte[] {0}); final ByteString s5 = new ByteString(new byte[]{15, 92}); assertThat(s.length(), is(8)); assertThat(s3.length(), is(0)); assertThat(s4.length(), is(1)); assertThat(s.hashCode(), is(s2.hashCode())); assertThat(s.equals(s2), is(true)); assertThat(s2.equals(s), is(true)); assertThat(s.equals(s3), is(false)); assertThat(s3.equals(s), is(false)); assertThat(s.toString(), is("030e0f5c00412300")); assertThat(s3.toString(), is("")); assertThat(s4.toString(), is("00")); assertThat(s.indexOf(s3), is(0)); assertThat(s.indexOf(s3, 5), is(5)); assertThat(s.indexOf(s3, 15), is(-1)); assertThat(s.indexOf(s4), is(4)); assertThat(s.indexOf(s4, 4), is(4)); assertThat(s.indexOf(s4, 5), is(7)); assertThat(s.indexOf(s5), is(2)); assertThat(s.indexOf(s5, 2), is(2));
private void thereAndBack(byte[] bytes) { final ByteString byteString = new ByteString(bytes); final byte[] bytes2 = byteString.getBytes(); assertThat(bytes, equalTo(bytes2)); final String base64String = byteString.toBase64String(); final ByteString byteString1 = ByteString.ofBase64(base64String); assertThat(byteString, equalTo(byteString1)); }
/** Converts a value from JDBC format to a type that can be serialized as * JSON. */ private static Object jdbcToSerial(ColumnMetaData.Rep rep, Object value, Calendar calendar) { switch (rep) { case BYTE_STRING: return new ByteString((byte[]) value).toBase64String(); case JAVA_UTIL_DATE: case JAVA_SQL_TIMESTAMP: case JAVA_SQL_DATE: case JAVA_SQL_TIME: long t = ((Date) value).getTime(); if (calendar != null) { t += calendar.getTimeZone().getOffset(t); } switch (rep) { case JAVA_SQL_DATE: return (int) DateTimeUtils.floorDiv(t, DateTimeUtils.MILLIS_PER_DAY); case JAVA_SQL_TIME: return (int) DateTimeUtils.floorMod(t, DateTimeUtils.MILLIS_PER_DAY); default: return t; } default: return value; } }
/** SQL {@code POSITION(seek IN string FROM integer)} function for byte * strings. */ public static int position(ByteString seek, ByteString s, int from) { final int from0 = from - 1; if (from0 > s.length() || from0 < 0) { return 0; } // ByteString doesn't have indexOf(ByteString, int) until avatica-1.9 // (see [CALCITE-1423]), so apply substring and find from there. Bug.upgrade("in avatica-1.9, use ByteString.substring(ByteString, int)"); final int p = s.substring(from0).indexOf(seek); if (p < 0) { return 0; } return p + from; }
/** SQL {@code TRIM} function applied to binary string. */ private static ByteString trim_(ByteString s, boolean left, boolean right) { int j = s.length(); if (right) { for (;;) { if (j == 0) { return ByteString.EMPTY; } if (s.byteAt(j - 1) != 0) { break; } --j; } } int i = 0; if (left) { for (;;) { if (i == j) { return ByteString.EMPTY; } if (s.byteAt(i) != 0) { break; } ++i; } } return s.substring(i, j); }
/** * Returns a ByteString that consists of a given range. * * @param start Start of range * @param end Position after end of range * @return Substring */ public ByteString substring(int start, int end) { byte[] bytes = Arrays.copyOfRange(this.bytes, start, end); return new ByteString(bytes, false); }
@Override public byte[] getBytes() { Object obj = getObject(); try { final ByteString o = (ByteString) obj; return o == null ? null : o.getBytes(); } catch (Exception ex) { return obj == null ? null : (byte[]) obj; } }
private static Object serialToJdbc(ColumnMetaData.Rep type, Object value, Calendar calendar) { switch (type) { case BYTE_STRING: return ByteString.ofBase64((String) value).getBytes(); case JAVA_UTIL_DATE: return new java.util.Date(adjust((Number) value, calendar)); case JAVA_SQL_DATE: return new java.sql.Date( adjust(((Number) value).longValue() * DateTimeUtils.MILLIS_PER_DAY, calendar)); case JAVA_SQL_TIME: return new java.sql.Time(adjust((Number) value, calendar)); case JAVA_SQL_TIMESTAMP: return new java.sql.Timestamp(adjust((Number) value, calendar)); default: return serialToLocal(type, value); } }
/** * Returns this byte string in a given base. * * @return String in given base */ public String toString(int base) { return toString(bytes, base); }
/** * Creates a byte string from a Base64 string. * * @param string Base64 string * @return Byte string */ public static ByteString ofBase64(String string) { final byte[] bytes = parseBase64(string); return new ByteString(bytes, false); }
/** * Creates a byte string from a hexadecimal or binary string. * * <p>For example, <code>of("DEAD", 16)</code> * returns the same as {@code ByteString(new byte[] {0xDE, 0xAD})}. * * @param string Array of bytes * @param base Base (2 or 16) * @return String */ public static ByteString of(String string, int base) { final byte[] bytes = parse(string, base); return new ByteString(bytes, false); }
/** SQL <code>></code> operator applied to ByteString values. */ public static boolean gt(ByteString b0, ByteString b1) { return b0.compareTo(b1) > 0; }
@Override public byte[] getBytes() throws SQLException { Object obj = getObject(); if (null == obj) { return null; } if (obj instanceof ByteString) { return ((ByteString) obj).getBytes(); } else if (obj instanceof String) { // Need to unwind the base64 for JSON return ByteString.parseBase64((String) obj); } else if (obj instanceof byte[]) { // Protobuf would have a byte array return (byte[]) obj; } else { throw new RuntimeException("Cannot handle " + obj.getClass() + " as bytes"); } }