001/*
002// This software is subject to the terms of the Eclipse Public License v1.0
003// Agreement, available at the following URL:
004// http://www.eclipse.org/legal/epl-v10.html.
005// You must accept the terms of that agreement to use this software.
006//
007// Copyright (C) 2011-2011 Pentaho and others
008// All Rights Reserved.
009*/
010package mondrian.util;
011
012import java.io.Serializable;
013import java.util.Arrays;
014
015/**
016 * Collection of bytes.
017 *
018 * <p>ByteString is to bytes what {@link String} is to chars: It is immutable,
019 * implements equality (hashCode and equals), comparison (compareTo) and
020 * serialization correctly.</p>
021 *
022 * @author jhyde
023 */
024public class ByteString implements Comparable<ByteString>, Serializable {
025    private final byte[] bytes;
026
027    private static final char[] digits = {
028        '0', '1', '2', '3', '4', '5', '6', '7',
029        '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
030    };
031
032    /**
033     * Creates a ByteString.
034     *
035     * @param bytes Bytes
036     */
037    public ByteString(byte[] bytes) {
038        this.bytes = bytes.clone();
039    }
040
041    @Override
042    public int hashCode() {
043        return Arrays.hashCode(bytes);
044    }
045
046    @Override
047    public boolean equals(Object obj) {
048        return obj instanceof ByteString
049            && Arrays.equals(bytes, ((ByteString) obj).bytes);
050    }
051
052    public int compareTo(ByteString that) {
053        final byte[] v1 = bytes;
054        final byte[] v2 = that.bytes;
055        final int n = Math.min(v1.length, v2.length);
056        for (int i = 0; i < n; i++) {
057            byte c1 = v1[i];
058            byte c2 = v2[i];
059            if (c1 != c2) {
060                return c1 - c2;
061            }
062        }
063        return v1.length - v2.length;
064    }
065
066    /**
067     * Returns this byte string in hexadecimal format.
068     *
069     * @return Hexadecimal string
070     */
071    @Override
072    public String toString() {
073        char[] chars = new char[bytes.length * 2];
074        for (int i = 0, j = 0; i < bytes.length; i++) {
075            byte b = bytes[i];
076            chars[j++] = digits[(b & 0xF0) >> 4];
077            chars[j++] = digits[b & 0x0F];
078        }
079        return new String(chars);
080    }
081
082    @SuppressWarnings({
083        "CloneDoesntCallSuperClone",
084        "CloneDoesntDeclareCloneNotSupportedException"
085    })
086    @Override
087    public Object clone() {
088        return this;
089    }
090
091    /**
092     * Returns the number of bytes in this byte string.
093     *
094     * @return Length of this byte string
095     */
096    public int length() {
097        return bytes.length;
098    }
099
100    /**
101     * Returns the byte at a given position in the byte string.
102     *
103     * @param i Index
104     * @throws  IndexOutOfBoundsException
105     *          if the <tt>index</tt> argument is negative or not less than
106     *          <tt>length()</tt>
107     * @return Byte at given position
108     */
109    public byte byteAt(int i) {
110        return bytes[i];
111    }
112}
113
114// End ByteString.java