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 */
020package org.sonar.duplications.block;
021
022import java.nio.ByteBuffer;
023import java.nio.IntBuffer;
024import 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 */
032public 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}