mirror of https://github.com/OpenIdentityPlatform/OpenDJ.git

Matthew Swift
21.06.2011 6b7839d9d70958b85da5c9340a53d1f21bd12c31
Fix OPENDJ-291: Do not use String representation of byte[] when constructing attribute values and byte strings.
5 files modified
322 ■■■■ changed files
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/ByteSequence.java 43 ●●●● patch | view | raw | blame | history
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/ByteString.java 100 ●●●● patch | view | raw | blame | history
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/ByteStringBuilder.java 138 ●●●● patch | view | raw | blame | history
opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/ByteStringBuilderTestCase.java 18 ●●●●● patch | view | raw | blame | history
opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/ByteStringTestCase.java 23 ●●●●● patch | view | raw | blame | history
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/ByteSequence.java
@@ -23,6 +23,7 @@
 *
 *
 *      Copyright 2009 Sun Microsystems, Inc.
 *      Portions copyright 2011 ForgeRock AS
 */
package org.forgerock.opendj.ldap;
@@ -77,22 +78,23 @@
   * whether this byte sequence is less than, equal to, or greater than the
   * specified byte array sub-sequence.
   *
   * @param b
   * @param bytes
   *          The byte array to compare.
   * @param offset
   *          The offset of the sub-sequence in the byte array to be compared;
   *          must be non-negative and no larger than {@code b.length} .
   *          must be non-negative and no larger than {@code bytes.length} .
   * @param length
   *          The length of the sub-sequence in the byte array to be compared;
   *          must be non-negative and no larger than {@code b.length - offset}.
   *          must be non-negative and no larger than
   *          {@code bytes.length - offset}.
   * @return A negative integer, zero, or a positive integer depending on
   *         whether this byte sequence is less than, equal to, or greater than
   *         the specified byte array sub-sequence.
   * @throws IndexOutOfBoundsException
   *           If {@code offset} is negative or if {@code length} is negative or
   *           if {@code offset + length} is greater than {@code b.length}.
   *           if {@code offset + length} is greater than {@code bytes.length}.
   */
  int compareTo(byte[] b, int offset, int length)
  int compareTo(byte[] bytes, int offset, int length)
      throws IndexOutOfBoundsException;
@@ -122,20 +124,20 @@
   * An invocation of the form:
   *
   * <pre>
   * src.copyTo(b)
   * src.copyTo(bytes)
   * </pre>
   *
   * Behaves in exactly the same way as the invocation:
   *
   * <pre>
   * src.copyTo(b, 0);
   * src.copyTo(bytes, 0);
   * </pre>
   *
   * @param b
   * @param bytes
   *          The byte array to which bytes are to be copied.
   * @return The byte array.
   */
  byte[] copyTo(byte[] b);
  byte[] copyTo(byte[] bytes);
@@ -149,29 +151,29 @@
   * An invocation of the form:
   *
   * <pre>
   * src.copyTo(b, offset)
   * src.copyTo(bytes, offset)
   * </pre>
   *
   * Behaves in exactly the same way as the invocation:
   *
   * <pre>
   * int len = Math.min(src.length(), b.length - offset);
   * int len = Math.min(src.length(), bytes.length - offset);
   * for (int i = 0; i &lt; len; i++)
   *   b[offset + i] = src.get(i);
   *   bytes[offset + i] = src.get(i);
   * </pre>
   *
   * Except that it is potentially much more efficient.
   *
   * @param b
   * @param bytes
   *          The byte array to which bytes are to be copied.
   * @param offset
   *          The offset within the array of the first byte to be written; must
   *          be non-negative and no larger than b.length.
   *          be non-negative and no larger than bytes.length.
   * @return The byte array.
   * @throws IndexOutOfBoundsException
   *           If {@code offset} is negative.
   */
  byte[] copyTo(byte[] b, int offset) throws IndexOutOfBoundsException;
  byte[] copyTo(byte[] bytes, int offset) throws IndexOutOfBoundsException;
@@ -206,21 +208,22 @@
   * byte sequence. In order for it to be considered equal, the provided byte
   * array sub-sequence must contain the same bytes in the same order.
   *
   * @param b
   * @param bytes
   *          The byte array for which to make the determination.
   * @param offset
   *          The offset of the sub-sequence in the byte array to be compared;
   *          must be non-negative and no larger than {@code b.length} .
   *          must be non-negative and no larger than {@code bytes.length} .
   * @param length
   *          The length of the sub-sequence in the byte array to be compared;
   *          must be non-negative and no larger than {@code b.length - offset}.
   *          must be non-negative and no larger than
   *          {@code bytes.length - offset}.
   * @return {@code true} if the content of the provided byte array sub-sequence
   *         is equal to that of this byte sequence, or {@code false} if not.
   * @throws IndexOutOfBoundsException
   *           If {@code offset} is negative or if {@code length} is negative or
   *           if {@code offset + length} is greater than {@code b.length}.
   *           if {@code offset + length} is greater than {@code bytes.length}.
   */
  boolean equals(byte[] b, int offset, int length)
  boolean equals(byte[] bytes, int offset, int length)
      throws IndexOutOfBoundsException;
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/ByteString.java
@@ -34,6 +34,7 @@
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.Charset;
import java.util.Arrays;
import java.util.logging.Level;
import com.forgerock.opendj.util.StaticUtils;
@@ -108,11 +109,26 @@
  /**
   * Returns a byte string containing the provided object. If the object is an
   * instance of {@code ByteSequence} then it is converted to a byte string
   * using the {@code toByteString()} method. Otherwise a new byte string is
   * created containing the UTF-8 encoded bytes of the string representation of
   * the provided object.
   * Returns a byte string representation of the provided object. The object is
   * converted to a byte string as follows:
   * <ul>
   * <li>if the object is an instance of {@code ByteSequence} then this method
   * is equivalent to calling {@code o.toByteString()}
   * <li>if the object is a {@code byte[]} then this method is equivalent to
   * calling {@link #valueOf(byte[])}
   * <li>if the object is a {@code char[]} then this method is equivalent to
   * calling {@link #valueOf(char[])}
   * <li>for all other types of object this method is equivalent to calling
   * {@link #valueOf(String)} with the {@code toString()} representation of the
   * provided object.
   * </ul>
   * <b>Note:</b> this method treats {@code Long} and {@code Integer} objects
   * like any other type of {@code Object}. More specifically, the following
   * invocations are not equivalent:
   * <ul>
   * <li>{@code valueOf(0)} is not equivalent to {@code valueOf((Object) 0)}
   * <li>{@code valueOf(0L)} is not equivalent to {@code valueOf((Object) 0L)}
   * </ul>
   *
   * @param o
   *          The object to use.
@@ -124,9 +140,17 @@
    {
      return ((ByteSequence) o).toByteString();
    }
    else if (o instanceof byte[])
    {
      return valueOf((byte[]) o);
    }
    else if (o instanceof char[])
    {
      return valueOf((char[]) o);
    }
    else
    {
      return wrap(StaticUtils.getBytes(o.toString()));
      return valueOf(o.toString());
    }
  }
@@ -148,6 +172,23 @@
  /**
   * Returns a byte string containing the contents of the provided byte array.
   * <p>
   * This method differs from {@link #wrap(byte[])} in that it defensively
   * copies the provided byte array.
   *
   * @param bytes
   *          The byte array to use.
   * @return A byte string containing a copy of the provided byte array.
   */
  public static ByteString valueOf(final byte[] bytes)
  {
    return wrap(Arrays.copyOf(bytes, bytes.length));
  }
  /**
   * Returns a byte string containing the UTF-8 encoded bytes of the provided
   * char array.
   *
@@ -170,13 +211,13 @@
   * therefore, the byte array MUST NOT be altered directly after this method
   * returns.
   *
   * @param b
   * @param bytes
   *          The byte array to wrap.
   * @return The byte string that wraps the given byte array.
   */
  public static ByteString wrap(final byte[] b)
  public static ByteString wrap(final byte[] bytes)
  {
    return new ByteString(b, 0, b.length);
    return new ByteString(bytes, 0, bytes.length);
  }
@@ -188,24 +229,24 @@
   * therefore, the byte array MUST NOT be altered directly after this method
   * returns.
   *
   * @param b
   * @param bytes
   *          The byte array to wrap.
   * @param offset
   *          The offset of the byte array to be used; must be non-negative and
   *          no larger than {@code b.length} .
   *          no larger than {@code bytes.length} .
   * @param length
   *          The length of the byte array to be used; must be non-negative and
   *          no larger than {@code b.length - offset}.
   *          no larger than {@code bytes.length - offset}.
   * @return The byte string that wraps the given byte array.
   * @throws IndexOutOfBoundsException
   *           If {@code offset} is negative or if {@code length} is negative or
   *           if {@code offset + length} is greater than {@code b.length}.
   *           if {@code offset + length} is greater than {@code bytes.length}.
   */
  public static ByteString wrap(final byte[] b, final int offset,
  public static ByteString wrap(final byte[] bytes, final int offset,
      final int length) throws IndexOutOfBoundsException
  {
    checkArrayBounds(b, offset, length);
    return new ByteString(b, offset, length);
    checkArrayBounds(bytes, offset, length);
    return new ByteString(bytes, offset, length);
  }
@@ -457,11 +498,12 @@
  /**
   * {@inheritDoc}
   */
  public int compareTo(final byte[] b, final int offset, final int length)
  public int compareTo(final byte[] bytes, final int offset, final int length)
      throws IndexOutOfBoundsException
  {
    checkArrayBounds(b, offset, length);
    return compareTo(this.buffer, this.offset, this.length, b, offset, length);
    checkArrayBounds(bytes, offset, length);
    return compareTo(this.buffer, this.offset, this.length, bytes, offset,
        length);
  }
@@ -483,10 +525,10 @@
  /**
   * {@inheritDoc}
   */
  public byte[] copyTo(final byte[] b)
  public byte[] copyTo(final byte[] bytes)
  {
    copyTo(b, 0);
    return b;
    copyTo(bytes, 0);
    return bytes;
  }
@@ -494,16 +536,16 @@
  /**
   * {@inheritDoc}
   */
  public byte[] copyTo(final byte[] b, final int offset)
  public byte[] copyTo(final byte[] bytes, final int offset)
      throws IndexOutOfBoundsException
  {
    if (offset < 0)
    {
      throw new IndexOutOfBoundsException();
    }
    System.arraycopy(buffer, this.offset, b, offset, Math.min(length, b.length
        - offset));
    return b;
    System.arraycopy(buffer, this.offset, bytes, offset,
        Math.min(length, bytes.length - offset));
    return bytes;
  }
@@ -533,11 +575,11 @@
  /**
   * {@inheritDoc}
   */
  public boolean equals(final byte[] b, final int offset, final int length)
  public boolean equals(final byte[] bytes, final int offset, final int length)
      throws IndexOutOfBoundsException
  {
    checkArrayBounds(b, offset, length);
    return equals(this.buffer, this.offset, this.length, b, offset, length);
    checkArrayBounds(bytes, offset, length);
    return equals(this.buffer, this.offset, this.length, bytes, offset, length);
  }
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/ByteStringBuilder.java
@@ -23,6 +23,7 @@
 *
 *
 *      Copyright 2009 Sun Microsystems, Inc.
 *      Portions copyright 2011 ForgeRock AS
 */
package org.forgerock.opendj.ldap;
@@ -32,6 +33,8 @@
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.Charset;
import java.util.logging.Level;
import com.forgerock.opendj.util.StaticUtils;
@@ -364,22 +367,22 @@
   * An invocation of the form:
   *
   * <pre>
   * src.append(b)
   * src.append(bytes)
   * </pre>
   *
   * Behaves in exactly the same way as the invocation:
   *
   * <pre>
   * src.append(b, 0, b.length);
   * src.append(bytes, 0, bytes.length);
   * </pre>
   *
   * @param b
   * @param bytes
   *          The byte array to be appended to this byte string builder.
   * @return This byte string builder.
   */
  public ByteStringBuilder append(final byte[] b)
  public ByteStringBuilder append(final byte[] bytes)
  {
    return append(b, 0, b.length);
    return append(bytes, 0, bytes.length);
  }
@@ -387,28 +390,28 @@
  /**
   * Appends the provided byte array to this byte string builder.
   *
   * @param b
   * @param bytes
   *          The byte array to be appended to this byte string builder.
   * @param offset
   *          The offset of the byte array to be used; must be non-negative and
   *          no larger than {@code b.length} .
   *          no larger than {@code bytes.length} .
   * @param length
   *          The length of the byte array to be used; must be non-negative and
   *          no larger than {@code b.length - offset}.
   *          no larger than {@code bytes.length - offset}.
   * @return This byte string builder.
   * @throws IndexOutOfBoundsException
   *           If {@code offset} is negative or if {@code length} is negative or
   *           if {@code offset + length} is greater than {@code b.length}.
   *           if {@code offset + length} is greater than {@code bytes.length}.
   */
  public ByteStringBuilder append(final byte[] b, final int offset,
  public ByteStringBuilder append(final byte[] bytes, final int offset,
      final int length) throws IndexOutOfBoundsException
  {
    ByteString.checkArrayBounds(b, offset, length);
    ByteString.checkArrayBounds(bytes, offset, length);
    if (length != 0)
    {
      ensureAdditionalCapacity(length);
      System.arraycopy(b, offset, buffer, this.length, length);
      System.arraycopy(bytes, offset, buffer, this.length, length);
      this.length += length;
    }
@@ -498,6 +501,57 @@
  /**
   * Appends the UTF-8 encoded bytes of the provided
   * char array to this byte string
   * builder.
   *
   * @param chars
   *          The char array whose UTF-8 encoding is to be appended to this byte
   *          string builder.
   * @return This byte string builder.
   */
  public ByteStringBuilder append(final char[] chars)
  {
    if (chars == null)
    {
      return this;
    }
    // Assume that each char is 1 byte
    final int len = chars.length;
    ensureAdditionalCapacity(len);
    for (int i = 0; i < len; i++)
    {
      final char c = chars[i];
      final byte b = (byte) (c & 0x0000007F);
      if (c == b)
      {
        buffer[this.length + i] = b;
      }
      else
      {
        // There is a multi-byte char. Defer to JDK.
        final Charset utf8 = Charset.forName("UTF-8");
        final ByteBuffer byteBuffer = utf8.encode(CharBuffer.wrap(chars));
        final int remaining = byteBuffer.remaining();
        ensureAdditionalCapacity(remaining - len);
        byteBuffer.get(buffer, this.length, remaining);
        this.length += remaining;
        return this;
      }
    }
    // The 1 byte char assumption was correct
    this.length += len;
    return this;
  }
  /**
   * Appends the provided {@code InputStream} to this byte string builder.
   *
   * @param stream
@@ -578,11 +632,26 @@
  /**
   * Appends the provided object to this byte string builder. If the object is
   * an instance of {@code ByteSequence} then its contents will be appended
   * directly to this byte string builder using the {@code append(ByteSequence)}
   * method. Otherwise the string representation of the object will be appended
   * using the {@code append(String)} method.
   * Appends the byte string representation of the provided object to this byte
   * string builder. The object is converted to a byte string as follows:
   * <ul>
   * <li>if the object is an instance of {@code ByteSequence} then this method
   * is equivalent to calling {@link #append(ByteSequence)}
   * <li>if the object is a {@code byte[]} then this method is equivalent to
   * calling {@link #append(byte[])}
   * <li>if the object is a {@code char[]} then this method is equivalent to
   * calling {@link #append(char[])}
   * <li>for all other types of object this method is equivalent to calling
   * {@link #append(String)} with the {@code toString()} representation of the
   * provided object.
   * </ul>
   * <b>Note:</b> this method treats {@code Long} and {@code Integer} objects
   * like any other type of {@code Object}. More specifically, the following
   * invocations are not equivalent:
   * <ul>
   * <li>{@code append(0)} is not equivalent to {@code append((Object) 0)}
   * <li>{@code append(0L)} is not equivalent to {@code append((Object) 0L)}
   * </ul>
   *
   * @param o
   *          The object to be appended to this byte string builder.
@@ -598,6 +667,14 @@
    {
      return append((ByteSequence) o);
    }
    else if (o instanceof byte[])
    {
      return append((byte[]) o);
    }
    else if (o instanceof char[])
    {
      return append((char[]) o);
    }
    else
    {
      return append(o.toString());
@@ -795,11 +872,12 @@
  /**
   * {@inheritDoc}
   */
  public int compareTo(final byte[] b, final int offset, final int length)
  public int compareTo(final byte[] bytes, final int offset, final int length)
      throws IndexOutOfBoundsException
  {
    ByteString.checkArrayBounds(b, offset, length);
    return ByteString.compareTo(this.buffer, 0, this.length, b, offset, length);
    ByteString.checkArrayBounds(bytes, offset, length);
    return ByteString.compareTo(this.buffer, 0, this.length, bytes, offset,
        length);
  }
@@ -821,10 +899,10 @@
  /**
   * {@inheritDoc}
   */
  public byte[] copyTo(final byte[] b)
  public byte[] copyTo(final byte[] bytes)
  {
    copyTo(b, 0);
    return b;
    copyTo(bytes, 0);
    return bytes;
  }
@@ -832,15 +910,16 @@
  /**
   * {@inheritDoc}
   */
  public byte[] copyTo(final byte[] b, final int offset)
  public byte[] copyTo(final byte[] bytes, final int offset)
      throws IndexOutOfBoundsException
  {
    if (offset < 0)
    {
      throw new IndexOutOfBoundsException();
    }
    System.arraycopy(buffer, 0, b, offset, Math.min(length, b.length - offset));
    return b;
    System.arraycopy(buffer, 0, bytes, offset,
        Math.min(length, bytes.length - offset));
    return bytes;
  }
@@ -892,11 +971,12 @@
  /**
   * {@inheritDoc}
   */
  public boolean equals(final byte[] b, final int offset, final int length)
  public boolean equals(final byte[] bytes, final int offset, final int length)
      throws IndexOutOfBoundsException
  {
    ByteString.checkArrayBounds(b, offset, length);
    return ByteString.equals(this.buffer, 0, this.length, b, offset, length);
    ByteString.checkArrayBounds(bytes, offset, length);
    return ByteString
        .equals(this.buffer, 0, this.length, bytes, offset, length);
  }
opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/ByteStringBuilderTestCase.java
@@ -23,6 +23,7 @@
 *
 *
 *      Copyright 2010 Sun Microsystems, Inc.
 *      Portions copyright 2011 ForgeRock AS
 */
package org.forgerock.opendj.ldap;
@@ -258,6 +259,23 @@
        { new ByteStringBuilder(11).append("this is a").append(" test"),
            "this is a test".getBytes("UTF-8") },
        {
            new ByteStringBuilder().append((Object) "this is a").append(
                (Object) " test"), "this is a test".getBytes("UTF-8") },
        {
            new ByteStringBuilder().append("this is a".toCharArray()).append(
                " test".toCharArray()), "this is a test".getBytes("UTF-8") },
        {
            new ByteStringBuilder().append((Object) "this is a".toCharArray())
                .append((Object) " test".toCharArray()),
            "this is a test".getBytes("UTF-8") },
        {
            new ByteStringBuilder().append((Object) eightBytes).append(
                (Object) eightBytes),
            new byte[] { (byte) 0x01, (byte) 0x02, (byte) 0x03, (byte) 0x04,
                (byte) 0x05, (byte) 0x06, (byte) 0x07, (byte) 0x08,
                (byte) 0x01, (byte) 0x02, (byte) 0x03, (byte) 0x04,
                (byte) 0x05, (byte) 0x06, (byte) 0x07, (byte) 0x08 } },
        {
            new ByteStringBuilder().appendBERLength(0x00000000)
                .appendBERLength(0x00000001).appendBERLength(0x0000000F)
                .appendBERLength(0x00000010).appendBERLength(0x0000007F).
opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/ByteStringTestCase.java
@@ -23,6 +23,7 @@
 *
 *
 *      Copyright 2010 Sun Microsystems, Inc.
 *      Portions copyright 2011 ForgeRock AS
 */
package org.forgerock.opendj.ldap;
@@ -51,6 +52,10 @@
  @DataProvider(name = "byteSequenceProvider")
  public Object[][] byteSequenceProvider() throws Exception
  {
    byte[] testBytes = new byte[] { (byte) 0x01, (byte) 0x02, (byte) 0x03,
        (byte) 0x04, (byte) 0x05, (byte) 0x06, (byte) 0x07,
        (byte) 0x08 };
    return new Object[][] {
        { ByteString.empty(), new byte[0] },
        { ByteString.valueOf(1),
@@ -68,6 +73,12 @@
            new byte[] { (byte) 0x80, (byte) 0x00, (byte) 0x00, (byte) 0x00,
                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00 } },
        { ByteString.valueOf("cn=testvalue"), "cn=testvalue".getBytes("UTF-8") },
        { ByteString.valueOf((Object) "cn=testvalue"), "cn=testvalue".getBytes("UTF-8") },
        { ByteString.valueOf("cn=testvalue".toCharArray()), "cn=testvalue".getBytes("UTF-8") },
        { ByteString.valueOf((Object) "cn=testvalue".toCharArray()), "cn=testvalue".getBytes("UTF-8") },
        { ByteString.valueOf(testBytes), testBytes },
        { ByteString.valueOf((Object) testBytes), testBytes },
        { ByteString.valueOf(ByteString.valueOf("cn=testvalue")), "cn=testvalue".getBytes("UTF-8") },
        { ByteString.wrap(new byte[0]), new byte[0] },
        {
            ByteString
@@ -159,7 +170,7 @@
  @Test(dataProvider = "byteStringCharArrayProvider")
  public void testToCharArray(final String s)
  public void testFromStringToCharArray(final String s)
  {
    ByteString bs = ByteString.valueOf(s);
    Assert.assertTrue(Arrays.equals(bs.toCharArray(), s.toCharArray()));
@@ -168,6 +179,16 @@
  @Test(dataProvider = "byteStringCharArrayProvider")
  public void testFromCharArrayToCharArray(final String s)
  {
    final char[] chars = s.toCharArray();
    ByteString bs = ByteString.valueOf(chars);
    Assert.assertTrue(Arrays.equals(bs.toCharArray(), chars));
  }
  @Test(dataProvider = "byteStringCharArrayProvider")
  public void testValueOfCharArray(final String s)
  {
    ByteString bs = ByteString.valueOf(s.toCharArray());