blob: fa78f015612857e9745bf556237c9139012f7986 [file] [log] [blame]
// Copyright (C) 2015 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package com.google.gerrit.gpg;
import static com.google.common.base.Preconditions.checkArgument;
import org.eclipse.jgit.util.NB;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
public class Fingerprint {
private final byte[] fp;
public static String toString(byte[] fp) {
checkLength(fp);
return String.format(
"%04X %04X %04X %04X %04X %04X %04X %04X %04X %04X",
NB.decodeUInt16(fp, 0), NB.decodeUInt16(fp, 2), NB.decodeUInt16(fp, 4),
NB.decodeUInt16(fp, 6), NB.decodeUInt16(fp, 8), NB.decodeUInt16(fp, 10),
NB.decodeUInt16(fp, 12), NB.decodeUInt16(fp, 14),
NB.decodeUInt16(fp, 16), NB.decodeUInt16(fp, 18));
}
public static long getId(byte[] fp) {
return NB.decodeInt64(fp, 12);
}
public static Map<Long, Fingerprint> byId(Iterable<Fingerprint> fps) {
Map<Long, Fingerprint> result = new HashMap<>();
for (Fingerprint fp : fps) {
result.put(fp.getId(), fp);
}
return Collections.unmodifiableMap(result);
}
private static byte[] checkLength(byte[] fp) {
checkArgument(fp.length == 20,
"fingerprint must be 20 bytes, got %s", fp.length);
return fp;
}
/**
* Wrap a fingerprint byte array.
* <p>
* The newly created Fingerprint object takes ownership of the byte array,
* which must not be subsequently modified. (Most callers, such as hex
* decoders and {@code
* org.bouncycastle.openpgp.PGPPublicKey#getFingerprint()}, already produce
* fresh byte arrays).
*
* @param fp 20-byte fingerprint byte array to wrap.
*/
public Fingerprint(byte[] fp) {
this.fp = checkLength(fp);
}
/**
* Wrap a portion of a fingerprint byte array.
* <p>
* Unlike {@link #Fingerprint(byte[])}, creates a new copy of the byte array.
*
* @param buf byte array to wrap; must have at least {@code off + 20} bytes.
* @param off offset in buf.
*/
public Fingerprint(byte[] buf, int off) {
int expected = 20 + off;
checkArgument(buf.length >= expected,
"fingerprint buffer must have at least %s bytes, got %s",
expected, buf.length);
this.fp = new byte[20];
System.arraycopy(buf, off, fp, 0, 20);
}
public byte[] get() {
return fp;
}
public boolean equalsBytes(byte[] bytes) {
return Arrays.equals(fp, bytes);
}
@Override
public int hashCode() {
// Same hash code as ObjectId: second int word.
return NB.decodeInt32(fp, 4);
}
@Override
public boolean equals(Object o) {
return (o instanceof Fingerprint) && equalsBytes(((Fingerprint) o).fp);
}
@Override
public String toString() {
return toString(fp);
}
public long getId() {
return getId(fp);
}
}