001    /*
002     * Sonar, open source software quality management tool.
003     * Copyright (C) 2008-2012 SonarSource
004     * mailto:contact AT sonarsource DOT com
005     *
006     * Sonar is free software; you can redistribute it and/or
007     * modify it under the terms of the GNU Lesser General Public
008     * License as published by the Free Software Foundation; either
009     * version 3 of the License, or (at your option) any later version.
010     *
011     * Sonar is distributed in the hope that it will be useful,
012     * but WITHOUT ANY WARRANTY; without even the implied warranty of
013     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014     * Lesser General Public License for more details.
015     *
016     * You should have received a copy of the GNU Lesser General Public
017     * License along with Sonar; if not, write to the Free Software
018     * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02
019     */
020    package org.sonar.duplications.block;
021    
022    import java.nio.ByteBuffer;
023    import java.nio.IntBuffer;
024    import java.util.Arrays;
025    
026    /**
027     * Represents hash for {@link Block}. Immutable.
028     * 
029     * TODO Godin: would be better to rename to BlockHash,
030     * also maybe we can incorporate it into Block to reduce memory footprint during detection of duplicates
031     */
032    public final class ByteArray {
033    
034      private final byte[] bytes;
035    
036      /**
037       * Cache for hash code.
038       */
039      private int hash;
040    
041      public ByteArray(String hexString) {
042        int len = hexString.length();
043        this.bytes = new byte[len / 2];
044        for (int i = 0; i < len; i += 2) {
045          bytes[i / 2] = (byte) ((Character.digit(hexString.charAt(i), 16) << 4) + Character.digit(hexString.charAt(i + 1), 16));
046        }
047      }
048    
049      public ByteArray(byte[] bytes) {
050        this.bytes = new byte[bytes.length];
051        System.arraycopy(bytes, 0, this.bytes, 0, bytes.length);
052      }
053    
054      public ByteArray(long value) {
055        this.bytes = new byte[] {
056          (byte) (value >>> 56),
057          (byte) (value >>> 48),
058          (byte) (value >>> 40),
059          (byte) (value >>> 32),
060          (byte) (value >>> 24),
061          (byte) (value >>> 16),
062          (byte) (value >>> 8),
063          (byte) value };
064      }
065    
066      public ByteArray(int value) {
067        this.bytes = new byte[] {
068          (byte) (value >>> 24),
069          (byte) (value >>> 16),
070          (byte) (value >>> 8),
071          (byte) value };
072      }
073    
074      public ByteArray(int[] intArray) {
075        ByteBuffer bb = ByteBuffer.allocate(intArray.length * 4);
076        for (int i : intArray) {
077          bb.putInt(i);
078        }
079        this.bytes = bb.array();
080      }
081    
082      public int[] toIntArray() {
083        int size = (bytes.length / 4) + (bytes.length % 4 == 0 ? 0 : 1); // Pad the size to multiple of 4
084        ByteBuffer bb = ByteBuffer.allocate(size * 4);
085        bb.put(bytes);
086        bb.rewind();
087        IntBuffer ib = bb.asIntBuffer();
088        int[] result = new int[size];
089        ib.get(result);
090        return result;
091      }
092    
093      private static final String HEXES = "0123456789abcdef";
094    
095      public String toHexString() {
096        StringBuilder hex = new StringBuilder(2 * bytes.length);
097        for (byte b : bytes) {
098          hex.append(HEXES.charAt((b & 0xF0) >> 4)).append(HEXES.charAt((b & 0x0F)));
099        }
100        return hex.toString();
101      }
102    
103      @Override
104      public String toString() {
105        return toHexString();
106      }
107    
108      @Override
109      public boolean equals(Object o) {
110        if (this == o) {
111          return true;
112        }
113        if (o == null || getClass() != o.getClass()) {
114          return false;
115        }
116        ByteArray other = (ByteArray) o;
117        return Arrays.equals(bytes, other.bytes);
118      }
119    
120      @Override
121      public int hashCode() {
122        int h = hash;
123        int len = bytes.length;
124        if (h == 0 && len > 0) {
125          h = Arrays.hashCode(bytes);
126          hash = h;
127        }
128        return h;
129      }
130    
131    }