+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.lfs.lib;
+
+import java.io.Serializable;
+import java.text.MessageFormat;
+
+import org.eclipse.jgit.lfs.errors.InvalidLongObjectIdException;
+import org.eclipse.jgit.lfs.internal.LfsText;
+import org.eclipse.jgit.lib.AbbreviatedObjectId;
+import org.eclipse.jgit.lib.AnyObjectId;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.util.NB;
+import org.eclipse.jgit.util.RawParseUtils;
+
+/**
+ * A prefix abbreviation of an {@link LongObjectId}.
+ *
+ * Enable abbreviating SHA-256 strings used by Git LFS, using sufficient leading
+ * digits from the LongObjectId name to still be unique within the repository
+ * the string was generated from. These ids are likely to be unique for a useful
+ * period of time, especially if they contain at least 6-10 hex digits.
+ *
+ * This class converts the hex string into a binary form, to make it more
+ * efficient for matching against an object.
+ *
+ * Ported to SHA-256 from {@link AbbreviatedObjectId}
+ *
+ * @since 4.3
+ */
+public final class AbbreviatedLongObjectId implements Serializable {
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Test a string of characters to verify it is a hex format.
+ *
+ * If true the string can be parsed with {@link #fromString(String)}.
+ *
+ * @param id
+ * the string to test.
+ * @return true if the string can converted into an AbbreviatedObjectId.
+ */
+ public static final boolean isId(final String id) {
+ if (id.length() < 2
+ || Constants.LONG_OBJECT_ID_STRING_LENGTH < id.length())
+ return false;
+ try {
+ for (int i = 0; i < id.length(); i++)
+ RawParseUtils.parseHexInt4((byte) id.charAt(i));
+ return true;
+ } catch (ArrayIndexOutOfBoundsException e) {
+ return false;
+ }
+ }
+
+ /**
+ * Convert an AbbreviatedObjectId from hex characters (US-ASCII).
+ *
+ * @param buf
+ * the US-ASCII buffer to read from.
+ * @param offset
+ * position to read the first character from.
+ * @param end
+ * one past the last position to read (end-offset
is
+ * the length of the string).
+ * @return the converted object id.
+ */
+ public static final AbbreviatedLongObjectId fromString(final byte[] buf,
+ final int offset, final int end) {
+ if (end - offset > Constants.LONG_OBJECT_ID_STRING_LENGTH)
+ throw new IllegalArgumentException(MessageFormat.format(
+ LfsText.get().invalidLongIdLength,
+ Integer.valueOf(end - offset),
+ Integer.valueOf(Constants.LONG_OBJECT_ID_STRING_LENGTH)));
+ return fromHexString(buf, offset, end);
+ }
+
+ /**
+ * Convert an AbbreviatedObjectId from an {@link AnyObjectId}.
+ *
+ * This method copies over all bits of the Id, and is therefore complete
+ * (see {@link #isComplete()}).
+ *
+ * @param id
+ * the {@link ObjectId} to convert from.
+ * @return the converted object id.
+ */
+ public static final AbbreviatedLongObjectId fromLongObjectId(
+ AnyLongObjectId id) {
+ return new AbbreviatedLongObjectId(
+ Constants.LONG_OBJECT_ID_STRING_LENGTH, id.w1, id.w2, id.w3,
+ id.w4);
+ }
+
+ /**
+ * Convert an AbbreviatedLongObjectId from hex characters.
+ *
+ * @param str
+ * the string to read from. Must be <= 64 characters.
+ * @return the converted object id.
+ */
+ public static final AbbreviatedLongObjectId fromString(final String str) {
+ if (str.length() > Constants.LONG_OBJECT_ID_STRING_LENGTH)
+ throw new IllegalArgumentException(
+ MessageFormat.format(LfsText.get().invalidLongId, str));
+ final byte[] b = org.eclipse.jgit.lib.Constants.encodeASCII(str);
+ return fromHexString(b, 0, b.length);
+ }
+
+ private static final AbbreviatedLongObjectId fromHexString(final byte[] bs,
+ int ptr, final int end) {
+ try {
+ final long a = hexUInt64(bs, ptr, end);
+ final long b = hexUInt64(bs, ptr + 16, end);
+ final long c = hexUInt64(bs, ptr + 32, end);
+ final long d = hexUInt64(bs, ptr + 48, end);
+ return new AbbreviatedLongObjectId(end - ptr, a, b, c, d);
+ } catch (ArrayIndexOutOfBoundsException e1) {
+ throw new InvalidLongObjectIdException(bs, ptr, end - ptr);
+ }
+ }
+
+ private static final long hexUInt64(final byte[] bs, int p, final int end) {
+ if (16 <= end - p)
+ return RawParseUtils.parseHexInt64(bs, p);
+
+ long r = 0;
+ int n = 0;
+ while (n < 16 && p < end) {
+ r <<= 4;
+ r |= RawParseUtils.parseHexInt4(bs[p++]);
+ n++;
+ }
+ return r << (16 - n) * 4;
+ }
+
+ static long mask(final int nibbles, final long word, final long v) {
+ final long b = (word - 1) * 16;
+ if (b + 16 <= nibbles) {
+ // We have all of the bits required for this word.
+ //
+ return v;
+ }
+
+ if (nibbles <= b) {
+ // We have none of the bits required for this word.
+ //
+ return 0;
+ }
+
+ final long s = 64 - (nibbles - b) * 4;
+ return (v >>> s) << s;
+ }
+
+ /** Number of half-bytes used by this id. */
+ final int nibbles;
+
+ final long w1;
+
+ final long w2;
+
+ final long w3;
+
+ final long w4;
+
+ AbbreviatedLongObjectId(final int n, final long new_1, final long new_2,
+ final long new_3, final long new_4) {
+ nibbles = n;
+ w1 = new_1;
+ w2 = new_2;
+ w3 = new_3;
+ w4 = new_4;
+ }
+
+ /** @return number of hex digits appearing in this id */
+ public int length() {
+ return nibbles;
+ }
+
+ /** @return true if this ObjectId is actually a complete id. */
+ public boolean isComplete() {
+ return length() == Constants.LONG_OBJECT_ID_STRING_LENGTH;
+ }
+
+ /** @return a complete ObjectId; null if {@link #isComplete()} is false */
+ public LongObjectId toLongObjectId() {
+ return isComplete() ? new LongObjectId(w1, w2, w3, w4) : null;
+ }
+
+ /**
+ * Compares this abbreviation to a full object id.
+ *
+ * @param other
+ * the other object id.
+ * @return <0 if this abbreviation names an object that is less than
+ * other
; 0 if this abbreviation exactly matches the
+ * first {@link #length()} digits of other.name()
;
+ * >0 if this abbreviation names an object that is after
+ * other
.
+ */
+ public final int prefixCompare(final AnyLongObjectId other) {
+ int cmp;
+
+ cmp = NB.compareUInt64(w1, mask(1, other.w1));
+ if (cmp != 0)
+ return cmp;
+
+ cmp = NB.compareUInt64(w2, mask(2, other.w2));
+ if (cmp != 0)
+ return cmp;
+
+ cmp = NB.compareUInt64(w3, mask(3, other.w3));
+ if (cmp != 0)
+ return cmp;
+
+ return NB.compareUInt64(w4, mask(4, other.w4));
+ }
+
+ /**
+ * Compare this abbreviation to a network-byte-order LongObjectId.
+ *
+ * @param bs
+ * array containing the other LongObjectId in network byte order.
+ * @param p
+ * position within {@code bs} to start the compare at. At least
+ * 32 bytes, starting at this position are required.
+ * @return <0 if this abbreviation names an object that is less than
+ * other
; 0 if this abbreviation exactly matches the
+ * first {@link #length()} digits of other.name()
;
+ * >0 if this abbreviation names an object that is after
+ * other
.
+ */
+ public final int prefixCompare(final byte[] bs, final int p) {
+ int cmp;
+
+ cmp = NB.compareUInt64(w1, mask(1, NB.decodeInt64(bs, p)));
+ if (cmp != 0)
+ return cmp;
+
+ cmp = NB.compareUInt64(w2, mask(2, NB.decodeInt64(bs, p + 8)));
+ if (cmp != 0)
+ return cmp;
+
+ cmp = NB.compareUInt64(w3, mask(3, NB.decodeInt64(bs, p + 16)));
+ if (cmp != 0)
+ return cmp;
+
+ return NB.compareUInt64(w4, mask(4, NB.decodeInt64(bs, p + 24)));
+ }
+
+ /**
+ * Compare this abbreviation to a network-byte-order LongObjectId.
+ *
+ * @param bs
+ * array containing the other LongObjectId in network byte order.
+ * @param p
+ * position within {@code bs} to start the compare at. At least 4
+ * longs, starting at this position are required.
+ * @return <0 if this abbreviation names an object that is less than
+ * other
; 0 if this abbreviation exactly matches the
+ * first {@link #length()} digits of other.name()
;
+ * >0 if this abbreviation names an object that is after
+ * other
.
+ */
+ public final int prefixCompare(final long[] bs, final int p) {
+ int cmp;
+
+ cmp = NB.compareUInt64(w1, mask(1, bs[p]));
+ if (cmp != 0)
+ return cmp;
+
+ cmp = NB.compareUInt64(w2, mask(2, bs[p + 1]));
+ if (cmp != 0)
+ return cmp;
+
+ cmp = NB.compareUInt64(w3, mask(3, bs[p + 2]));
+ if (cmp != 0)
+ return cmp;
+
+ return NB.compareUInt64(w4, mask(4, bs[p + 3]));
+ }
+
+ /** @return value for a fan-out style map, only valid of length >= 2. */
+ public final int getFirstByte() {
+ return (int) (w1 >>> 56);
+ }
+
+ private long mask(final long word, final long v) {
+ return mask(nibbles, word, v);
+ }
+
+ @Override
+ public int hashCode() {
+ return (int) (w1 >> 32);
+ }
+
+ @Override
+ public boolean equals(final Object o) {
+ if (o instanceof AbbreviatedLongObjectId) {
+ final AbbreviatedLongObjectId b = (AbbreviatedLongObjectId) o;
+ return nibbles == b.nibbles && w1 == b.w1 && w2 == b.w2
+ && w3 == b.w3 && w4 == b.w4;
+ }
+ return false;
+ }
+
+ /**
+ * @return string form of the abbreviation, in lower case hexadecimal.
+ */
+ public final String name() {
+ final char[] b = new char[Constants.LONG_OBJECT_ID_STRING_LENGTH];
+
+ AnyLongObjectId.formatHexChar(b, 0, w1);
+ if (nibbles <= 16)
+ return new String(b, 0, nibbles);
+
+ AnyLongObjectId.formatHexChar(b, 16, w2);
+ if (nibbles <= 32)
+ return new String(b, 0, nibbles);
+
+ AnyLongObjectId.formatHexChar(b, 32, w3);
+ if (nibbles <= 48)
+ return new String(b, 0, nibbles);
+
+ AnyLongObjectId.formatHexChar(b, 48, w4);
+ return new String(b, 0, nibbles);
+ }
+
+ @SuppressWarnings("nls")
+ @Override
+ public String toString() {
+ return "AbbreviatedLongObjectId[" + name() + "]"; //$NON-NLS-1$
+ }
+}
diff --git a/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/lib/AnyLongObjectId.java b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/lib/AnyLongObjectId.java
new file mode 100644
index 000000000..1f0df882d
--- /dev/null
+++ b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/lib/AnyLongObjectId.java
@@ -0,0 +1,555 @@
+/*
+ * Copyright (C) 2015, Matthias Sohn
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.lfs.lib;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.Writer;
+import java.nio.ByteBuffer;
+
+import org.eclipse.jgit.lib.AnyObjectId;
+import org.eclipse.jgit.lib.ObjectReader;
+import org.eclipse.jgit.util.NB;
+
+/**
+ * A (possibly mutable) SHA-256 abstraction.
+ *
+ * If this is an instance of {@link MutableLongObjectId} the concept of equality
+ * with this instance can alter at any time, if this instance is modified to
+ * represent a different object name.
+ *
+ * Ported to SHA-256 from {@link AnyObjectId}
+ *
+ * @since 4.3
+ */
+public abstract class AnyLongObjectId implements Comparable {
+
+ /**
+ * Compare two object identifier byte sequences for equality.
+ *
+ * @param firstObjectId
+ * the first identifier to compare. Must not be null.
+ * @param secondObjectId
+ * the second identifier to compare. Must not be null.
+ * @return true if the two identifiers are the same.
+ */
+ public static boolean equals(final AnyLongObjectId firstObjectId,
+ final AnyLongObjectId secondObjectId) {
+ if (firstObjectId == secondObjectId)
+ return true;
+
+ // We test word 2 first as odds are someone already used our
+ // word 1 as a hash code, and applying that came up with these
+ // two instances we are comparing for equality. Therefore the
+ // first two words are very likely to be identical. We want to
+ // break away from collisions as quickly as possible.
+ //
+ return firstObjectId.w2 == secondObjectId.w2
+ && firstObjectId.w3 == secondObjectId.w3
+ && firstObjectId.w4 == secondObjectId.w4
+ && firstObjectId.w1 == secondObjectId.w1;
+ }
+
+ long w1;
+
+ long w2;
+
+ long w3;
+
+ long w4;
+
+ /**
+ * Get the first 8 bits of the LongObjectId.
+ *
+ * This is a faster version of {@code getByte(0)}.
+ *
+ * @return a discriminator usable for a fan-out style map. Returned values
+ * are unsigned and thus are in the range [0,255] rather than the
+ * signed byte range of [-128, 127].
+ */
+ public final int getFirstByte() {
+ return (int) (w1 >>> 56);
+ }
+
+ /**
+ * Get the second 8 bits of the LongObjectId.
+ *
+ * @return a discriminator usable for a fan-out style map. Returned values
+ * are unsigned and thus are in the range [0,255] rather than the
+ * signed byte range of [-128, 127].
+ */
+ public final int getSecondByte() {
+ return (int) ((w1 >>> 48) & 0xff);
+ }
+
+ /**
+ * Get any byte from the LongObjectId.
+ *
+ * Callers hard-coding {@code getByte(0)} should instead use the much faster
+ * special case variant {@link #getFirstByte()}.
+ *
+ * @param index
+ * index of the byte to obtain from the raw form of the
+ * LongObjectId. Must be in range [0,
+ * {@link Constants#LONG_OBJECT_ID_LENGTH}).
+ * @return the value of the requested byte at {@code index}. Returned values
+ * are unsigned and thus are in the range [0,255] rather than the
+ * signed byte range of [-128, 127].
+ * @throws ArrayIndexOutOfBoundsException
+ * {@code index} is less than 0, equal to
+ * {@link Constants#LONG_OBJECT_ID_LENGTH}, or greater than
+ * {@link Constants#LONG_OBJECT_ID_LENGTH}.
+ */
+ public final int getByte(int index) {
+ long w;
+ switch (index >> 3) {
+ case 0:
+ w = w1;
+ break;
+ case 1:
+ w = w2;
+ break;
+ case 2:
+ w = w3;
+ break;
+ case 3:
+ w = w4;
+ break;
+ default:
+ throw new ArrayIndexOutOfBoundsException(index);
+ }
+
+ return (int) ((w >>> (8 * (15 - (index & 15)))) & 0xff);
+ }
+
+ /**
+ * Compare this LongObjectId to another and obtain a sort ordering.
+ *
+ * @param other
+ * the other id to compare to. Must not be null.
+ * @return < 0 if this id comes before other; 0 if this id is equal to
+ * other; > 0 if this id comes after other.
+ */
+ public final int compareTo(final AnyLongObjectId other) {
+ if (this == other)
+ return 0;
+
+ int cmp;
+
+ cmp = NB.compareUInt64(w1, other.w1);
+ if (cmp != 0)
+ return cmp;
+
+ cmp = NB.compareUInt64(w2, other.w2);
+ if (cmp != 0)
+ return cmp;
+
+ cmp = NB.compareUInt64(w3, other.w3);
+ if (cmp != 0)
+ return cmp;
+
+ return NB.compareUInt64(w4, other.w4);
+ }
+
+ /**
+ * Compare this LongObjectId to a network-byte-order LongObjectId.
+ *
+ * @param bs
+ * array containing the other LongObjectId in network byte order.
+ * @param p
+ * position within {@code bs} to start the compare at. At least
+ * 32 bytes, starting at this position are required.
+ * @return a negative integer, zero, or a positive integer as this object is
+ * less than, equal to, or greater than the specified object.
+ */
+ public final int compareTo(final byte[] bs, final int p) {
+ int cmp;
+
+ cmp = NB.compareUInt64(w1, NB.decodeInt64(bs, p));
+ if (cmp != 0)
+ return cmp;
+
+ cmp = NB.compareUInt64(w2, NB.decodeInt64(bs, p + 8));
+ if (cmp != 0)
+ return cmp;
+
+ cmp = NB.compareUInt64(w3, NB.decodeInt64(bs, p + 16));
+ if (cmp != 0)
+ return cmp;
+
+ return NB.compareUInt64(w4, NB.decodeInt64(bs, p + 24));
+ }
+
+ /**
+ * Compare this LongObjectId to a network-byte-order LongObjectId.
+ *
+ * @param bs
+ * array containing the other LongObjectId in network byte order.
+ * @param p
+ * position within {@code bs} to start the compare at. At least 4
+ * longs, starting at this position are required.
+ * @return a negative integer, zero, or a positive integer as this object is
+ * less than, equal to, or greater than the specified object.
+ */
+ public final int compareTo(final long[] bs, final int p) {
+ int cmp;
+
+ cmp = NB.compareUInt64(w1, bs[p]);
+ if (cmp != 0)
+ return cmp;
+
+ cmp = NB.compareUInt64(w2, bs[p + 1]);
+ if (cmp != 0)
+ return cmp;
+
+ cmp = NB.compareUInt64(w3, bs[p + 2]);
+ if (cmp != 0)
+ return cmp;
+
+ return NB.compareUInt64(w4, bs[p + 3]);
+ }
+
+ /**
+ * Tests if this LongObjectId starts with the given abbreviation.
+ *
+ * @param abbr
+ * the abbreviation.
+ * @return true if this LongObjectId begins with the abbreviation; else
+ * false.
+ */
+ public boolean startsWith(final AbbreviatedLongObjectId abbr) {
+ return abbr.prefixCompare(this) == 0;
+ }
+
+ public final int hashCode() {
+ return (int) (w1 >> 32);
+ }
+
+ /**
+ * Determine if this LongObjectId has exactly the same value as another.
+ *
+ * @param other
+ * the other id to compare to. May be null.
+ * @return true only if both LongObjectIds have identical bits.
+ */
+ public final boolean equals(final AnyLongObjectId other) {
+ return other != null ? equals(this, other) : false;
+ }
+
+ public final boolean equals(final Object o) {
+ if (o instanceof AnyLongObjectId)
+ return equals((AnyLongObjectId) o);
+ else
+ return false;
+ }
+
+ /**
+ * Copy this LongObjectId to an output writer in raw binary.
+ *
+ * @param w
+ * the buffer to copy to. Must be in big endian order.
+ */
+ public void copyRawTo(final ByteBuffer w) {
+ w.putLong(w1);
+ w.putLong(w2);
+ w.putLong(w3);
+ w.putLong(w4);
+ }
+
+ /**
+ * Copy this LongObjectId to a byte array.
+ *
+ * @param b
+ * the buffer to copy to.
+ * @param o
+ * the offset within b to write at.
+ */
+ public void copyRawTo(final byte[] b, final int o) {
+ NB.encodeInt64(b, o, w1);
+ NB.encodeInt64(b, o + 8, w2);
+ NB.encodeInt64(b, o + 16, w3);
+ NB.encodeInt64(b, o + 24, w4);
+ }
+
+ /**
+ * Copy this LongObjectId to an long array.
+ *
+ * @param b
+ * the buffer to copy to.
+ * @param o
+ * the offset within b to write at.
+ */
+ public void copyRawTo(final long[] b, final int o) {
+ b[o] = w1;
+ b[o + 1] = w2;
+ b[o + 2] = w3;
+ b[o + 3] = w4;
+ }
+
+ /**
+ * Copy this LongObjectId to an output writer in raw binary.
+ *
+ * @param w
+ * the stream to write to.
+ * @throws IOException
+ * the stream writing failed.
+ */
+ public void copyRawTo(final OutputStream w) throws IOException {
+ writeRawLong(w, w1);
+ writeRawLong(w, w2);
+ writeRawLong(w, w3);
+ writeRawLong(w, w4);
+ }
+
+ private static void writeRawLong(final OutputStream w, long v)
+ throws IOException {
+ w.write((int) (v >>> 56));
+ w.write((int) (v >>> 48));
+ w.write((int) (v >>> 40));
+ w.write((int) (v >>> 32));
+ w.write((int) (v >>> 24));
+ w.write((int) (v >>> 16));
+ w.write((int) (v >>> 8));
+ w.write((int) v);
+ }
+
+ /**
+ * Copy this LongObjectId to an output writer in hex format.
+ *
+ * @param w
+ * the stream to copy to.
+ * @throws IOException
+ * the stream writing failed.
+ */
+ public void copyTo(final OutputStream w) throws IOException {
+ w.write(toHexByteArray());
+ }
+
+ /**
+ * Copy this LongObjectId to a byte array in hex format.
+ *
+ * @param b
+ * the buffer to copy to.
+ * @param o
+ * the offset within b to write at.
+ */
+ public void copyTo(byte[] b, int o) {
+ formatHexByte(b, o + 0, w1);
+ formatHexByte(b, o + 16, w2);
+ formatHexByte(b, o + 32, w3);
+ formatHexByte(b, o + 48, w4);
+ }
+
+ /**
+ * Copy this LongObjectId to a ByteBuffer in hex format.
+ *
+ * @param b
+ * the buffer to copy to.
+ */
+ public void copyTo(ByteBuffer b) {
+ b.put(toHexByteArray());
+ }
+
+ private byte[] toHexByteArray() {
+ final byte[] dst = new byte[Constants.LONG_OBJECT_ID_STRING_LENGTH];
+ formatHexByte(dst, 0, w1);
+ formatHexByte(dst, 16, w2);
+ formatHexByte(dst, 32, w3);
+ formatHexByte(dst, 48, w4);
+ return dst;
+ }
+
+ private static final byte[] hexbyte = { '0', '1', '2', '3', '4', '5', '6',
+ '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
+
+ private static void formatHexByte(final byte[] dst, final int p, long w) {
+ int o = p + 15;
+ while (o >= p && w != 0) {
+ dst[o--] = hexbyte[(int) (w & 0xf)];
+ w >>>= 4;
+ }
+ while (o >= p)
+ dst[o--] = '0';
+ }
+
+ /**
+ * Copy this LongObjectId to an output writer in hex format.
+ *
+ * @param w
+ * the stream to copy to.
+ * @throws IOException
+ * the stream writing failed.
+ */
+ public void copyTo(final Writer w) throws IOException {
+ w.write(toHexCharArray());
+ }
+
+ /**
+ * Copy this LongObjectId to an output writer in hex format.
+ *
+ * @param tmp
+ * temporary char array to buffer construct into before writing.
+ * Must be at least large enough to hold 2 digits for each byte
+ * of object id (64 characters or larger).
+ * @param w
+ * the stream to copy to.
+ * @throws IOException
+ * the stream writing failed.
+ */
+ public void copyTo(final char[] tmp, final Writer w) throws IOException {
+ toHexCharArray(tmp);
+ w.write(tmp, 0, Constants.LONG_OBJECT_ID_STRING_LENGTH);
+ }
+
+ /**
+ * Copy this LongObjectId to a StringBuilder in hex format.
+ *
+ * @param tmp
+ * temporary char array to buffer construct into before writing.
+ * Must be at least large enough to hold 2 digits for each byte
+ * of object id (64 characters or larger).
+ * @param w
+ * the string to append onto.
+ */
+ public void copyTo(final char[] tmp, final StringBuilder w) {
+ toHexCharArray(tmp);
+ w.append(tmp, 0, Constants.LONG_OBJECT_ID_STRING_LENGTH);
+ }
+
+ char[] toHexCharArray() {
+ final char[] dst = new char[Constants.LONG_OBJECT_ID_STRING_LENGTH];
+ toHexCharArray(dst);
+ return dst;
+ }
+
+ private void toHexCharArray(final char[] dst) {
+ formatHexChar(dst, 0, w1);
+ formatHexChar(dst, 16, w2);
+ formatHexChar(dst, 32, w3);
+ formatHexChar(dst, 48, w4);
+ }
+
+ private static final char[] hexchar = { '0', '1', '2', '3', '4', '5', '6',
+ '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
+
+ static void formatHexChar(final char[] dst, final int p, long w) {
+ int o = p + 15;
+ while (o >= p && w != 0) {
+ dst[o--] = hexchar[(int) (w & 0xf)];
+ w >>>= 4;
+ }
+ while (o >= p)
+ dst[o--] = '0';
+ }
+
+ @SuppressWarnings("nls")
+ @Override
+ public String toString() {
+ return "AnyLongObjectId[" + name() + "]";
+ }
+
+ /**
+ * @return string form of the SHA-256, in lower case hexadecimal.
+ */
+ public final String name() {
+ return new String(toHexCharArray());
+ }
+
+ /**
+ * @return string form of the SHA-256, in lower case hexadecimal.
+ */
+ public final String getName() {
+ return name();
+ }
+
+ /**
+ * Return an abbreviation (prefix) of this object SHA-256.
+ *
+ * This implementation does not guarantee uniqueness. Callers should instead
+ * use {@link ObjectReader#abbreviate(AnyObjectId, int)} to obtain a unique
+ * abbreviation within the scope of a particular object database.
+ *
+ * @param len
+ * length of the abbreviated string.
+ * @return SHA-256 abbreviation.
+ */
+ public AbbreviatedLongObjectId abbreviate(final int len) {
+ final long a = AbbreviatedLongObjectId.mask(len, 1, w1);
+ final long b = AbbreviatedLongObjectId.mask(len, 2, w2);
+ final long c = AbbreviatedLongObjectId.mask(len, 3, w3);
+ final long d = AbbreviatedLongObjectId.mask(len, 4, w4);
+ return new AbbreviatedLongObjectId(len, a, b, c, d);
+ }
+
+ /**
+ * Obtain an immutable copy of this current object.
+ *
+ * Only returns this
if this instance is an unsubclassed
+ * instance of {@link LongObjectId}; otherwise a new instance is returned
+ * holding the same value.
+ *
+ * This method is useful to shed any additional memory that may be tied to
+ * the subclass, yet retain the unique identity of the object id for future
+ * lookups within maps and repositories.
+ *
+ * @return an immutable copy, using the smallest memory footprint possible.
+ */
+ public final LongObjectId copy() {
+ if (getClass() == LongObjectId.class)
+ return (LongObjectId) this;
+ return new LongObjectId(this);
+ }
+
+ /**
+ * Obtain an immutable copy of this current object.
+ *
+ * See {@link #copy()} if this
is a possibly subclassed (but
+ * immutable) identity and the application needs a lightweight identity
+ * only reference.
+ *
+ * @return an immutable copy. May be this
if this is already an
+ * immutable instance.
+ */
+ public abstract LongObjectId toObjectId();
+}
diff --git a/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/lib/Constants.java b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/lib/Constants.java
new file mode 100644
index 000000000..92a5c4250
--- /dev/null
+++ b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/lib/Constants.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2015, Matthias Sohn
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.eclipse.jgit.lfs.lib;
+
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.text.MessageFormat;
+
+import org.eclipse.jgit.lfs.internal.LfsText;
+
+/**
+ * Misc. constants used throughout JGit LFS extension.
+ *
+ * @since 4.3
+ **/
+@SuppressWarnings("nls")
+public final class Constants {
+ /** Hash function used natively by Git LFS extension for large objects. */
+ private static final String LONG_HASH_FUNCTION = "SHA-256";
+
+ /**
+ * A Git LFS large object hash is 256 bits, i.e. 32 bytes.
+ *
+ * Changing this assumption is not going to be as easy as changing this
+ * declaration.
+ */
+ public static final int LONG_OBJECT_ID_LENGTH = 32;
+
+ /**
+ * A Git LFS large object can be expressed as a 64 character string of
+ * hexadecimal digits.
+ *
+ * @see #LONG_OBJECT_ID_LENGTH
+ */
+ public static final int LONG_OBJECT_ID_STRING_LENGTH = LONG_OBJECT_ID_LENGTH
+ * 2;
+
+ /**
+ * Create a new digest function for objects.
+ *
+ * @return a new digest object.
+ * @throws RuntimeException
+ * this Java virtual machine does not support the required hash
+ * function. Very unlikely given that JGit uses a hash function
+ * that is in the Java reference specification.
+ */
+ public static MessageDigest newMessageDigest() {
+ try {
+ return MessageDigest.getInstance(LONG_HASH_FUNCTION);
+ } catch (NoSuchAlgorithmException nsae) {
+ throw new RuntimeException(MessageFormat.format(
+ LfsText.get().requiredHashFunctionNotAvailable,
+ LONG_HASH_FUNCTION), nsae);
+ }
+ }
+
+ static {
+ if (LONG_OBJECT_ID_LENGTH != newMessageDigest().getDigestLength())
+ throw new LinkageError(
+ LfsText.get().incorrectLONG_OBJECT_ID_LENGTH);
+ }
+}
diff --git a/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/lib/LongObjectId.java b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/lib/LongObjectId.java
new file mode 100644
index 000000000..c4a4e43b1
--- /dev/null
+++ b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/lib/LongObjectId.java
@@ -0,0 +1,309 @@
+/*
+ * Copyright (C) 2015, Matthias Sohn
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.lfs.lib;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+
+import org.eclipse.jgit.lfs.errors.InvalidLongObjectIdException;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.util.NB;
+import org.eclipse.jgit.util.RawParseUtils;
+
+/**
+ * A SHA-256 abstraction.
+ *
+ * Ported to SHA-256 from {@link ObjectId}
+ *
+ * @since 4.3
+ */
+public class LongObjectId extends AnyLongObjectId implements Serializable {
+ private static final long serialVersionUID = 1L;
+
+ private static final LongObjectId ZEROID;
+
+ private static final String ZEROID_STR;
+
+ static {
+ ZEROID = new LongObjectId(0L, 0L, 0L, 0L);
+ ZEROID_STR = ZEROID.name();
+ }
+
+ /**
+ * Get the special all-zero LongObjectId.
+ *
+ * @return the all-zero LongObjectId, often used to stand-in for no object.
+ */
+ public static final LongObjectId zeroId() {
+ return ZEROID;
+ }
+
+ /**
+ * Test a string of characters to verify that it can be interpreted as
+ * LongObjectId.
+ *
+ * If true the string can be parsed with {@link #fromString(String)}.
+ *
+ * @param id
+ * the string to test.
+ * @return true if the string can converted into an LongObjectId.
+ */
+ public static final boolean isId(final String id) {
+ if (id.length() != Constants.LONG_OBJECT_ID_STRING_LENGTH)
+ return false;
+ try {
+ for (int i = 0; i < Constants.LONG_OBJECT_ID_STRING_LENGTH; i++) {
+ RawParseUtils.parseHexInt4((byte) id.charAt(i));
+ }
+ return true;
+ } catch (ArrayIndexOutOfBoundsException e) {
+ return false;
+ }
+ }
+
+ /**
+ * Convert a LongObjectId into a hex string representation.
+ *
+ * @param i
+ * the id to convert. May be null.
+ * @return the hex string conversion of this id's content.
+ */
+ public static final String toString(final LongObjectId i) {
+ return i != null ? i.name() : ZEROID_STR;
+ }
+
+ /**
+ * Compare two object identifier byte sequences for equality.
+ *
+ * @param firstBuffer
+ * the first buffer to compare against. Must have at least 32
+ * bytes from position fi through the end of the buffer.
+ * @param fi
+ * first offset within firstBuffer to begin testing.
+ * @param secondBuffer
+ * the second buffer to compare against. Must have at least 32
+ * bytes from position si through the end of the buffer.
+ * @param si
+ * first offset within secondBuffer to begin testing.
+ * @return true if the two identifiers are the same.
+ */
+ public static boolean equals(final byte[] firstBuffer, final int fi,
+ final byte[] secondBuffer, final int si) {
+ return firstBuffer[fi] == secondBuffer[si]
+ && firstBuffer[fi + 1] == secondBuffer[si + 1]
+ && firstBuffer[fi + 2] == secondBuffer[si + 2]
+ && firstBuffer[fi + 3] == secondBuffer[si + 3]
+ && firstBuffer[fi + 4] == secondBuffer[si + 4]
+ && firstBuffer[fi + 5] == secondBuffer[si + 5]
+ && firstBuffer[fi + 6] == secondBuffer[si + 6]
+ && firstBuffer[fi + 7] == secondBuffer[si + 7]
+ && firstBuffer[fi + 8] == secondBuffer[si + 8]
+ && firstBuffer[fi + 9] == secondBuffer[si + 9]
+ && firstBuffer[fi + 10] == secondBuffer[si + 10]
+ && firstBuffer[fi + 11] == secondBuffer[si + 11]
+ && firstBuffer[fi + 12] == secondBuffer[si + 12]
+ && firstBuffer[fi + 13] == secondBuffer[si + 13]
+ && firstBuffer[fi + 14] == secondBuffer[si + 14]
+ && firstBuffer[fi + 15] == secondBuffer[si + 15]
+ && firstBuffer[fi + 16] == secondBuffer[si + 16]
+ && firstBuffer[fi + 17] == secondBuffer[si + 17]
+ && firstBuffer[fi + 18] == secondBuffer[si + 18]
+ && firstBuffer[fi + 19] == secondBuffer[si + 19]
+ && firstBuffer[fi + 20] == secondBuffer[si + 20]
+ && firstBuffer[fi + 21] == secondBuffer[si + 21]
+ && firstBuffer[fi + 22] == secondBuffer[si + 22]
+ && firstBuffer[fi + 23] == secondBuffer[si + 23]
+ && firstBuffer[fi + 24] == secondBuffer[si + 24]
+ && firstBuffer[fi + 25] == secondBuffer[si + 25]
+ && firstBuffer[fi + 26] == secondBuffer[si + 26]
+ && firstBuffer[fi + 27] == secondBuffer[si + 27]
+ && firstBuffer[fi + 28] == secondBuffer[si + 28]
+ && firstBuffer[fi + 29] == secondBuffer[si + 29]
+ && firstBuffer[fi + 30] == secondBuffer[si + 30]
+ && firstBuffer[fi + 31] == secondBuffer[si + 31];
+ }
+
+ /**
+ * Convert a LongObjectId from raw binary representation.
+ *
+ * @param bs
+ * the raw byte buffer to read from. At least 32 bytes must be
+ * available within this byte array.
+ * @return the converted object id.
+ */
+ public static final LongObjectId fromRaw(final byte[] bs) {
+ return fromRaw(bs, 0);
+ }
+
+ /**
+ * Convert a LongObjectId from raw binary representation.
+ *
+ * @param bs
+ * the raw byte buffer to read from. At least 32 bytes after p
+ * must be available within this byte array.
+ * @param p
+ * position to read the first byte of data from.
+ * @return the converted object id.
+ */
+ public static final LongObjectId fromRaw(final byte[] bs, final int p) {
+ final long a = NB.decodeInt64(bs, p);
+ final long b = NB.decodeInt64(bs, p + 8);
+ final long c = NB.decodeInt64(bs, p + 16);
+ final long d = NB.decodeInt64(bs, p + 24);
+ return new LongObjectId(a, b, c, d);
+ }
+
+ /**
+ * Convert a LongObjectId from raw binary representation.
+ *
+ * @param is
+ * the raw long buffer to read from. At least 4 longs must be
+ * available within this long array.
+ * @return the converted object id.
+ */
+ public static final LongObjectId fromRaw(final long[] is) {
+ return fromRaw(is, 0);
+ }
+
+ /**
+ * Convert a LongObjectId from raw binary representation.
+ *
+ * @param is
+ * the raw long buffer to read from. At least 4 longs after p
+ * must be available within this long array.
+ * @param p
+ * position to read the first long of data from.
+ * @return the converted object id.
+ */
+ public static final LongObjectId fromRaw(final long[] is, final int p) {
+ return new LongObjectId(is[p], is[p + 1], is[p + 2], is[p + 3]);
+ }
+
+ /**
+ * Convert a LongObjectId from hex characters (US-ASCII).
+ *
+ * @param buf
+ * the US-ASCII buffer to read from. At least 64 bytes after
+ * offset must be available within this byte array.
+ * @param offset
+ * position to read the first character from.
+ * @return the converted object id.
+ */
+ public static final LongObjectId fromString(final byte[] buf, final int offset) {
+ return fromHexString(buf, offset);
+ }
+
+ /**
+ * Convert a LongObjectId from hex characters.
+ *
+ * @param str
+ * the string to read from. Must be 64 characters long.
+ * @return the converted object id.
+ */
+ public static LongObjectId fromString(final String str) {
+ if (str.length() != Constants.LONG_OBJECT_ID_STRING_LENGTH)
+ throw new InvalidLongObjectIdException(str);
+ return fromHexString(org.eclipse.jgit.lib.Constants.encodeASCII(str),
+ 0);
+ }
+
+ private static final LongObjectId fromHexString(final byte[] bs, int p) {
+ try {
+ final long a = RawParseUtils.parseHexInt64(bs, p);
+ final long b = RawParseUtils.parseHexInt64(bs, p + 16);
+ final long c = RawParseUtils.parseHexInt64(bs, p + 32);
+ final long d = RawParseUtils.parseHexInt64(bs, p + 48);
+ return new LongObjectId(a, b, c, d);
+ } catch (ArrayIndexOutOfBoundsException e1) {
+ throw new InvalidLongObjectIdException(bs, p,
+ Constants.LONG_OBJECT_ID_STRING_LENGTH);
+ }
+ }
+
+ LongObjectId(final long new_1, final long new_2, final long new_3,
+ final long new_4) {
+ w1 = new_1;
+ w2 = new_2;
+ w3 = new_3;
+ w4 = new_4;
+ }
+
+ /**
+ * Initialize this instance by copying another existing LongObjectId.
+ *
+ * This constructor is mostly useful for subclasses which want to extend a
+ * LongObjectId with more properties, but initialize from an existing
+ * LongObjectId instance acquired by other means.
+ *
+ * @param src
+ * another already parsed LongObjectId to copy the value out of.
+ */
+ protected LongObjectId(final AnyLongObjectId src) {
+ w1 = src.w1;
+ w2 = src.w2;
+ w3 = src.w3;
+ w4 = src.w4;
+ }
+
+ @Override
+ public LongObjectId toObjectId() {
+ return this;
+ }
+
+ private void writeObject(ObjectOutputStream os) throws IOException {
+ os.writeLong(w1);
+ os.writeLong(w2);
+ os.writeLong(w3);
+ os.writeLong(w4);
+ }
+
+ private void readObject(ObjectInputStream ois) throws IOException {
+ w1 = ois.readLong();
+ w2 = ois.readLong();
+ w3 = ois.readLong();
+ w4 = ois.readLong();
+ }
+}
diff --git a/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/lib/MutableLongObjectId.java b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/lib/MutableLongObjectId.java
new file mode 100644
index 000000000..130e94ed0
--- /dev/null
+++ b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/lib/MutableLongObjectId.java
@@ -0,0 +1,256 @@
+/*
+ * Copyright (C) 2015, Matthias Sohn
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.lfs.lib;
+
+import java.text.MessageFormat;
+
+import org.eclipse.jgit.lfs.errors.InvalidLongObjectIdException;
+import org.eclipse.jgit.lfs.internal.LfsText;
+import org.eclipse.jgit.lib.MutableObjectId;
+import org.eclipse.jgit.util.NB;
+import org.eclipse.jgit.util.RawParseUtils;
+
+/**
+ * A mutable SHA-256 abstraction.
+ *
+ * Ported to SHA-256 from {@link MutableObjectId}
+ *
+ * @since 4.3
+ */
+public class MutableLongObjectId extends AnyLongObjectId {
+ /**
+ * Empty constructor. Initialize object with default (zeros) value.
+ */
+ public MutableLongObjectId() {
+ super();
+ }
+
+ /**
+ * Copying constructor.
+ *
+ * @param src
+ * original entry, to copy id from
+ */
+ MutableLongObjectId(MutableLongObjectId src) {
+ fromObjectId(src);
+ }
+
+ /**
+ * Set any byte in the id.
+ *
+ * @param index
+ * index of the byte to set in the raw form of the ObjectId. Must
+ * be in range [0, {@link Constants#LONG_OBJECT_ID_LENGTH}).
+ * @param value
+ * the value of the specified byte at {@code index}. Values are
+ * unsigned and thus are in the range [0,255] rather than the
+ * signed byte range of [-128, 127].
+ * @throws ArrayIndexOutOfBoundsException
+ * {@code index} is less than 0, equal to
+ * {@link Constants#LONG_OBJECT_ID_LENGTH}, or greater than
+ * {@link Constants#LONG_OBJECT_ID_LENGTH}.
+ */
+ public void setByte(int index, int value) {
+ switch (index >> 3) {
+ case 0:
+ w1 = set(w1, index & 7, value);
+ break;
+ case 1:
+ w2 = set(w2, index & 7, value);
+ break;
+ case 2:
+ w3 = set(w3, index & 7, value);
+ break;
+ case 3:
+ w4 = set(w4, index & 7, value);
+ break;
+ default:
+ throw new ArrayIndexOutOfBoundsException(index);
+ }
+ }
+
+ private static long set(long w, int index, long value) {
+ value &= 0xff;
+
+ switch (index) {
+ case 0:
+ return (w & 0x00ffffffffffffffL) | (value << 56);
+ case 1:
+ return (w & 0xff00ffffffffffffL) | (value << 48);
+ case 2:
+ return (w & 0xffff00ffffffffffL) | (value << 40);
+ case 3:
+ return (w & 0xffffff00ffffffffL) | (value << 32);
+ case 4:
+ return (w & 0xffffffff00ffffffL) | (value << 24);
+ case 5:
+ return (w & 0xffffffffff00ffffL) | (value << 16);
+ case 6:
+ return (w & 0xffffffffffff00ffL) | (value << 8);
+ case 7:
+ return (w & 0xffffffffffffff00L) | value;
+ default:
+ throw new ArrayIndexOutOfBoundsException();
+ }
+ }
+
+ /** Make this id match {@link LongObjectId#zeroId()}. */
+ public void clear() {
+ w1 = 0;
+ w2 = 0;
+ w3 = 0;
+ w4 = 0;
+ }
+
+ /**
+ * Copy an LongObjectId into this mutable buffer.
+ *
+ * @param src
+ * the source id to copy from.
+ */
+ public void fromObjectId(AnyLongObjectId src) {
+ this.w1 = src.w1;
+ this.w2 = src.w2;
+ this.w3 = src.w3;
+ this.w4 = src.w4;
+ }
+
+ /**
+ * Convert an LongObjectId from raw binary representation.
+ *
+ * @param bs
+ * the raw byte buffer to read from. At least 32 bytes must be
+ * available within this byte array.
+ */
+ public void fromRaw(final byte[] bs) {
+ fromRaw(bs, 0);
+ }
+
+ /**
+ * Convert an LongObjectId from raw binary representation.
+ *
+ * @param bs
+ * the raw byte buffer to read from. At least 32 bytes after p
+ * must be available within this byte array.
+ * @param p
+ * position to read the first byte of data from.
+ */
+ public void fromRaw(final byte[] bs, final int p) {
+ w1 = NB.decodeInt64(bs, p);
+ w2 = NB.decodeInt64(bs, p + 8);
+ w3 = NB.decodeInt64(bs, p + 16);
+ w4 = NB.decodeInt64(bs, p + 24);
+ }
+
+ /**
+ * Convert an LongObjectId from binary representation expressed in integers.
+ *
+ * @param longs
+ * the raw long buffer to read from. At least 4 longs must be
+ * available within this longs array.
+ */
+ public void fromRaw(final long[] longs) {
+ fromRaw(longs, 0);
+ }
+
+ /**
+ * Convert an LongObjectId from binary representation expressed in longs.
+ *
+ * @param longs
+ * the raw int buffer to read from. At least 4 longs after p must
+ * be available within this longs array.
+ * @param p
+ * position to read the first integer of data from.
+ *
+ */
+ public void fromRaw(final long[] longs, final int p) {
+ w1 = longs[p];
+ w2 = longs[p + 1];
+ w3 = longs[p + 2];
+ w4 = longs[p + 3];
+ }
+
+ /**
+ * Convert an LongObjectId from hex characters (US-ASCII).
+ *
+ * @param buf
+ * the US-ASCII buffer to read from. At least 32 bytes after
+ * offset must be available within this byte array.
+ * @param offset
+ * position to read the first character from.
+ */
+ public void fromString(final byte[] buf, final int offset) {
+ fromHexString(buf, offset);
+ }
+
+ /**
+ * Convert an LongObjectId from hex characters.
+ *
+ * @param str
+ * the string to read from. Must be 64 characters long.
+ */
+ public void fromString(final String str) {
+ if (str.length() != Constants.LONG_OBJECT_ID_STRING_LENGTH)
+ throw new IllegalArgumentException(
+ MessageFormat.format(LfsText.get().invalidLongId, str));
+ fromHexString(org.eclipse.jgit.lib.Constants.encodeASCII(str), 0);
+ }
+
+ private void fromHexString(final byte[] bs, int p) {
+ try {
+ w1 = RawParseUtils.parseHexInt64(bs, p);
+ w2 = RawParseUtils.parseHexInt64(bs, p + 16);
+ w3 = RawParseUtils.parseHexInt64(bs, p + 32);
+ w4 = RawParseUtils.parseHexInt64(bs, p + 48);
+ } catch (ArrayIndexOutOfBoundsException e1) {
+ throw new InvalidLongObjectIdException(bs, p,
+ Constants.LONG_OBJECT_ID_STRING_LENGTH);
+ }
+ }
+
+ @Override
+ public LongObjectId toObjectId() {
+ return new LongObjectId(this);
+ }
+}
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.lfs.feature/.gitignore b/org.eclipse.jgit.packaging/org.eclipse.jgit.lfs.feature/.gitignore
new file mode 100644
index 000000000..2f7896d1d
--- /dev/null
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.lfs.feature/.gitignore
@@ -0,0 +1 @@
+target/
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.lfs.feature/.project b/org.eclipse.jgit.packaging/org.eclipse.jgit.lfs.feature/.project
new file mode 100644
index 000000000..c2061b9a5
--- /dev/null
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.lfs.feature/.project
@@ -0,0 +1,17 @@
+
+
+ org.eclipse.jgit.lfs.feature
+
+
+
+
+
+ org.eclipse.pde.FeatureBuilder
+
+
+
+
+
+ org.eclipse.pde.FeatureNature
+
+
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.lfs.feature/.settings/org.eclipse.core.resources.prefs b/org.eclipse.jgit.packaging/org.eclipse.jgit.lfs.feature/.settings/org.eclipse.core.resources.prefs
new file mode 100644
index 000000000..14bdc2c70
--- /dev/null
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.lfs.feature/.settings/org.eclipse.core.resources.prefs
@@ -0,0 +1,3 @@
+#Fri Jun 18 23:33:45 CEST 2010
+eclipse.preferences.version=1
+encoding/=UTF-8
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.lfs.feature/.settings/org.eclipse.core.runtime.prefs b/org.eclipse.jgit.packaging/org.eclipse.jgit.lfs.feature/.settings/org.eclipse.core.runtime.prefs
new file mode 100644
index 000000000..898252b4d
--- /dev/null
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.lfs.feature/.settings/org.eclipse.core.runtime.prefs
@@ -0,0 +1,3 @@
+#Fri Jun 18 23:33:45 CEST 2010
+eclipse.preferences.version=1
+line.separator=\n
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.lfs.feature/.settings/org.eclipse.mylyn.tasks.ui.prefs b/org.eclipse.jgit.packaging/org.eclipse.jgit.lfs.feature/.settings/org.eclipse.mylyn.tasks.ui.prefs
new file mode 100644
index 000000000..823c0f56a
--- /dev/null
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.lfs.feature/.settings/org.eclipse.mylyn.tasks.ui.prefs
@@ -0,0 +1,4 @@
+#Tue Jul 19 20:11:28 CEST 2011
+eclipse.preferences.version=1
+project.repository.kind=bugzilla
+project.repository.url=https\://bugs.eclipse.org/bugs
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.lfs.feature/.settings/org.eclipse.mylyn.team.ui.prefs b/org.eclipse.jgit.packaging/org.eclipse.jgit.lfs.feature/.settings/org.eclipse.mylyn.team.ui.prefs
new file mode 100644
index 000000000..0cba949fb
--- /dev/null
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.lfs.feature/.settings/org.eclipse.mylyn.team.ui.prefs
@@ -0,0 +1,3 @@
+#Tue Jul 19 20:11:28 CEST 2011
+commit.comment.template=${task.description} \n\nBug\: ${task.key}
+eclipse.preferences.version=1
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.lfs.feature/build.properties b/org.eclipse.jgit.packaging/org.eclipse.jgit.lfs.feature/build.properties
new file mode 100644
index 000000000..b4a8dde9e
--- /dev/null
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.lfs.feature/build.properties
@@ -0,0 +1,4 @@
+bin.includes = feature.xml,\
+ edl-v10.html,\
+ feature.properties,\
+ license.html
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.lfs.feature/edl-v10.html b/org.eclipse.jgit.packaging/org.eclipse.jgit.lfs.feature/edl-v10.html
new file mode 100644
index 000000000..1826b47af
--- /dev/null
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.lfs.feature/edl-v10.html
@@ -0,0 +1,59 @@
+
+
+
+
+
+
+Eclipse Distribution License - Version 1.0
+
+
+
+
+
+
+Eclipse Distribution License - v 1.0
+
+Copyright (c) 2007, Eclipse Foundation, Inc. and its licensors.
+
+All rights reserved.
+Redistribution and use in source and binary forms, with or without modification,
+ are permitted provided that the following conditions are met:
+
- Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+- Neither the name of the Eclipse Foundation, Inc. nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+
+
+
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.lfs.feature/feature.properties b/org.eclipse.jgit.packaging/org.eclipse.jgit.lfs.feature/feature.properties
new file mode 100644
index 000000000..c5bffa8f2
--- /dev/null
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.lfs.feature/feature.properties
@@ -0,0 +1,159 @@
+###############################################################################
+# Copyright (c) 20015 Matthias Sohn and others.
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/epl-v10.html
+#
+###############################################################################
+
+featureName=Java implementation of Git - optional LFS support
+providerName=Eclipse JGit
+
+updateSiteName=Eclipse JGit Update Site
+
+# description property - text of the "Feature Description"
+description=\
+Optional LFS support.\n
+################ end of description property ##################################
+
+# "copyright" property - text of the "Feature Update Copyright"
+copyright=\
+Copyright (c) 2015, Matthias Sohn et.al.\n\
+All rights reserved. This program and the accompanying materials\n\
+are made available under the terms of the Eclipse Distribution License v1.0\n\
+which accompanies this distribution, and is available at\n\
+http://www.eclipse.org/org/documents/edl-v10.html\n
+################ end of copyright property ####################################
+
+# "licenseURL" property - URL of the "Feature License"
+# do not translate value - just change to point to a locale-specific HTML page
+licenseURL=license.html
+
+# "license" property - text of the "Feature Update License"
+# should be plain text version of license agreement pointed to be "licenseURL"
+license=\
+Eclipse Foundation Software User Agreement\n\
+April 9, 2014\n\
+\n\
+Usage Of Content\n\
+\n\
+THE ECLIPSE FOUNDATION MAKES AVAILABLE SOFTWARE, DOCUMENTATION, INFORMATION AND/OR\n\
+OTHER MATERIALS FOR OPEN SOURCE PROJECTS (COLLECTIVELY "CONTENT").\n\
+USE OF THE CONTENT IS GOVERNED BY THE TERMS AND CONDITIONS OF THIS\n\
+AGREEMENT AND/OR THE TERMS AND CONDITIONS OF LICENSE AGREEMENTS OR\n\
+NOTICES INDICATED OR REFERENCED BELOW. BY USING THE CONTENT, YOU\n\
+AGREE THAT YOUR USE OF THE CONTENT IS GOVERNED BY THIS AGREEMENT\n\
+AND/OR THE TERMS AND CONDITIONS OF ANY APPLICABLE LICENSE AGREEMENTS\n\
+OR NOTICES INDICATED OR REFERENCED BELOW. IF YOU DO NOT AGREE TO THE\n\
+TERMS AND CONDITIONS OF THIS AGREEMENT AND THE TERMS AND CONDITIONS\n\
+OF ANY APPLICABLE LICENSE AGREEMENTS OR NOTICES INDICATED OR REFERENCED\n\
+BELOW, THEN YOU MAY NOT USE THE CONTENT.\n\
+\n\
+Applicable Licenses\n\
+\n\
+Unless otherwise indicated, all Content made available by the\n\
+Eclipse Foundation is provided to you under the terms and conditions of\n\
+the Eclipse Public License Version 1.0 ("EPL"). A copy of the EPL is\n\
+provided with this Content and is also available at http://www.eclipse.org/legal/epl-v10.html.\n\
+For purposes of the EPL, "Program" will mean the Content.\n\
+\n\
+Content includes, but is not limited to, source code, object code,\n\
+documentation and other files maintained in the Eclipse Foundation source code\n\
+repository ("Repository") in software modules ("Modules") and made available\n\
+as downloadable archives ("Downloads").\n\
+\n\
+ - Content may be structured and packaged into modules to facilitate delivering,\n\
+ extending, and upgrading the Content. Typical modules may include plug-ins ("Plug-ins"),\n\
+ plug-in fragments ("Fragments"), and features ("Features").\n\
+ - Each Plug-in or Fragment may be packaged as a sub-directory or JAR (Java(TM) ARchive)\n\
+ in a directory named "plugins".\n\
+ - A Feature is a bundle of one or more Plug-ins and/or Fragments and associated material.\n\
+ Each Feature may be packaged as a sub-directory in a directory named "features".\n\
+ Within a Feature, files named "feature.xml" may contain a list of the names and version\n\
+ numbers of the Plug-ins and/or Fragments associated with that Feature.\n\
+ - Features may also include other Features ("Included Features"). Within a Feature, files\n\
+ named "feature.xml" may contain a list of the names and version numbers of Included Features.\n\
+\n\
+The terms and conditions governing Plug-ins and Fragments should be\n\
+contained in files named "about.html" ("Abouts"). The terms and\n\
+conditions governing Features and Included Features should be contained\n\
+in files named "license.html" ("Feature Licenses"). Abouts and Feature\n\
+Licenses may be located in any directory of a Download or Module\n\
+including, but not limited to the following locations:\n\
+\n\
+ - The top-level (root) directory\n\
+ - Plug-in and Fragment directories\n\
+ - Inside Plug-ins and Fragments packaged as JARs\n\
+ - Sub-directories of the directory named "src" of certain Plug-ins\n\
+ - Feature directories\n\
+\n\
+Note: if a Feature made available by the Eclipse Foundation is installed using the\n\
+Provisioning Technology (as defined below), you must agree to a license ("Feature \n\
+Update License") during the installation process. If the Feature contains\n\
+Included Features, the Feature Update License should either provide you\n\
+with the terms and conditions governing the Included Features or inform\n\
+you where you can locate them. Feature Update Licenses may be found in\n\
+the "license" property of files named "feature.properties" found within a Feature.\n\
+Such Abouts, Feature Licenses, and Feature Update Licenses contain the\n\
+terms and conditions (or references to such terms and conditions) that\n\
+govern your use of the associated Content in that directory.\n\
+\n\
+THE ABOUTS, FEATURE LICENSES, AND FEATURE UPDATE LICENSES MAY REFER\n\
+TO THE EPL OR OTHER LICENSE AGREEMENTS, NOTICES OR TERMS AND CONDITIONS.\n\
+SOME OF THESE OTHER LICENSE AGREEMENTS MAY INCLUDE (BUT ARE NOT LIMITED TO):\n\
+\n\
+ - Eclipse Distribution License Version 1.0 (available at http://www.eclipse.org/licenses/edl-v1.0.html)\n\
+ - Common Public License Version 1.0 (available at http://www.eclipse.org/legal/cpl-v10.html)\n\
+ - Apache Software License 1.1 (available at http://www.apache.org/licenses/LICENSE)\n\
+ - Apache Software License 2.0 (available at http://www.apache.org/licenses/LICENSE-2.0)\n\
+ - Mozilla Public License Version 1.1 (available at http://www.mozilla.org/MPL/MPL-1.1.html)\n\
+\n\
+IT IS YOUR OBLIGATION TO READ AND ACCEPT ALL SUCH TERMS AND CONDITIONS PRIOR\n\
+TO USE OF THE CONTENT. If no About, Feature License, or Feature Update License\n\
+is provided, please contact the Eclipse Foundation to determine what terms and conditions\n\
+govern that particular Content.\n\
+\n\
+\n\Use of Provisioning Technology\n\
+\n\
+The Eclipse Foundation makes available provisioning software, examples of which include,\n\
+but are not limited to, p2 and the Eclipse Update Manager ("Provisioning Technology") for\n\
+the purpose of allowing users to install software, documentation, information and/or\n\
+other materials (collectively "Installable Software"). This capability is provided with\n\
+the intent of allowing such users to install, extend and update Eclipse-based products.\n\
+Information about packaging Installable Software is available at\n\
+http://eclipse.org/equinox/p2/repository_packaging.html ("Specification").\n\
+\n\
+You may use Provisioning Technology to allow other parties to install Installable Software.\n\
+You shall be responsible for enabling the applicable license agreements relating to the\n\
+Installable Software to be presented to, and accepted by, the users of the Provisioning Technology\n\
+in accordance with the Specification. By using Provisioning Technology in such a manner and\n\
+making it available in accordance with the Specification, you further acknowledge your\n\
+agreement to, and the acquisition of all necessary rights to permit the following:\n\
+\n\
+ 1. A series of actions may occur ("Provisioning Process") in which a user may execute\n\
+ the Provisioning Technology on a machine ("Target Machine") with the intent of installing,\n\
+ extending or updating the functionality of an Eclipse-based product.\n\
+ 2. During the Provisioning Process, the Provisioning Technology may cause third party\n\
+ Installable Software or a portion thereof to be accessed and copied to the Target Machine.\n\
+ 3. Pursuant to the Specification, you will provide to the user the terms and conditions that\n\
+ govern the use of the Installable Software ("Installable Software Agreement") and such\n\
+ Installable Software Agreement shall be accessed from the Target Machine in accordance\n\
+ with the Specification. Such Installable Software Agreement must inform the user of the\n\
+ terms and conditions that govern the Installable Software and must solicit acceptance by\n\
+ the end user in the manner prescribed in such Installable Software Agreement. Upon such\n\
+ indication of agreement by the user, the provisioning Technology will complete installation\n\
+ of the Installable Software.\n\
+\n\
+Cryptography\n\
+\n\
+Content may contain encryption software. The country in which you are\n\
+currently may have restrictions on the import, possession, and use,\n\
+and/or re-export to another country, of encryption software. BEFORE\n\
+using any encryption software, please check the country's laws,\n\
+regulations and policies concerning the import, possession, or use, and\n\
+re-export of encryption software, to see if this is permitted.\n\
+\n\
+Java and all Java-based trademarks are trademarks of Oracle Corporation in the United States, other countries, or both.\n
+########### end of license property ##########################################
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.lfs.feature/feature.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.lfs.feature/feature.xml
new file mode 100644
index 000000000..e8f74f4aa
--- /dev/null
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.lfs.feature/feature.xml
@@ -0,0 +1,36 @@
+
+
+
+
+ %description
+
+
+
+ %copyright
+
+
+
+ %license
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.lfs.feature/license.html b/org.eclipse.jgit.packaging/org.eclipse.jgit.lfs.feature/license.html
new file mode 100644
index 000000000..95ad95e77
--- /dev/null
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.lfs.feature/license.html
@@ -0,0 +1,106 @@
+
+
+
+
+Eclipse Foundation Software User Agreement
+
+
+
+Eclipse Foundation Software User Agreement
+April 9, 2014
+
+Usage Of Content
+
+THE ECLIPSE FOUNDATION MAKES AVAILABLE SOFTWARE, DOCUMENTATION, INFORMATION AND/OR OTHER MATERIALS FOR OPEN SOURCE PROJECTS
+ (COLLECTIVELY "CONTENT"). USE OF THE CONTENT IS GOVERNED BY THE TERMS AND CONDITIONS OF THIS AGREEMENT AND/OR THE TERMS AND
+ CONDITIONS OF LICENSE AGREEMENTS OR NOTICES INDICATED OR REFERENCED BELOW. BY USING THE CONTENT, YOU AGREE THAT YOUR USE
+ OF THE CONTENT IS GOVERNED BY THIS AGREEMENT AND/OR THE TERMS AND CONDITIONS OF ANY APPLICABLE LICENSE AGREEMENTS OR
+ NOTICES INDICATED OR REFERENCED BELOW. IF YOU DO NOT AGREE TO THE TERMS AND CONDITIONS OF THIS AGREEMENT AND THE TERMS AND
+ CONDITIONS OF ANY APPLICABLE LICENSE AGREEMENTS OR NOTICES INDICATED OR REFERENCED BELOW, THEN YOU MAY NOT USE THE CONTENT.
+
+Applicable Licenses
+
+Unless otherwise indicated, all Content made available by the Eclipse Foundation is provided to you under the terms and conditions of the Eclipse Public License Version 1.0
+ ("EPL"). A copy of the EPL is provided with this Content and is also available at http://www.eclipse.org/legal/epl-v10.html.
+ For purposes of the EPL, "Program" will mean the Content.
+
+Content includes, but is not limited to, source code, object code, documentation and other files maintained in the Eclipse Foundation source code
+ repository ("Repository") in software modules ("Modules") and made available as downloadable archives ("Downloads").
+
+
+ - Content may be structured and packaged into modules to facilitate delivering, extending, and upgrading the Content. Typical modules may include plug-ins ("Plug-ins"), plug-in fragments ("Fragments"), and features ("Features").
+ - Each Plug-in or Fragment may be packaged as a sub-directory or JAR (Java™ ARchive) in a directory named "plugins".
+ - A Feature is a bundle of one or more Plug-ins and/or Fragments and associated material. Each Feature may be packaged as a sub-directory in a directory named "features". Within a Feature, files named "feature.xml" may contain a list of the names and version numbers of the Plug-ins
+ and/or Fragments associated with that Feature.
+ - Features may also include other Features ("Included Features"). Within a Feature, files named "feature.xml" may contain a list of the names and version numbers of Included Features.
+
+
+The terms and conditions governing Plug-ins and Fragments should be contained in files named "about.html" ("Abouts"). The terms and conditions governing Features and
+Included Features should be contained in files named "license.html" ("Feature Licenses"). Abouts and Feature Licenses may be located in any directory of a Download or Module
+including, but not limited to the following locations:
+
+
+ - The top-level (root) directory
+ - Plug-in and Fragment directories
+ - Inside Plug-ins and Fragments packaged as JARs
+ - Sub-directories of the directory named "src" of certain Plug-ins
+ - Feature directories
+
+
+Note: if a Feature made available by the Eclipse Foundation is installed using the Provisioning Technology (as defined below), you must agree to a license ("Feature Update License") during the
+installation process. If the Feature contains Included Features, the Feature Update License should either provide you with the terms and conditions governing the Included Features or
+inform you where you can locate them. Feature Update Licenses may be found in the "license" property of files named "feature.properties" found within a Feature.
+Such Abouts, Feature Licenses, and Feature Update Licenses contain the terms and conditions (or references to such terms and conditions) that govern your use of the associated Content in
+that directory.
+
+THE ABOUTS, FEATURE LICENSES, AND FEATURE UPDATE LICENSES MAY REFER TO THE EPL OR OTHER LICENSE AGREEMENTS, NOTICES OR TERMS AND CONDITIONS. SOME OF THESE
+OTHER LICENSE AGREEMENTS MAY INCLUDE (BUT ARE NOT LIMITED TO):
+
+
+
+IT IS YOUR OBLIGATION TO READ AND ACCEPT ALL SUCH TERMS AND CONDITIONS PRIOR TO USE OF THE CONTENT. If no About, Feature License, or Feature Update License is provided, please
+contact the Eclipse Foundation to determine what terms and conditions govern that particular Content.
+
+
+Use of Provisioning Technology
+
+The Eclipse Foundation makes available provisioning software, examples of which include, but are not limited to, p2 and the Eclipse
+ Update Manager ("Provisioning Technology") for the purpose of allowing users to install software, documentation, information and/or
+ other materials (collectively "Installable Software"). This capability is provided with the intent of allowing such users to
+ install, extend and update Eclipse-based products. Information about packaging Installable Software is available at http://eclipse.org/equinox/p2/repository_packaging.html
+ ("Specification").
+
+You may use Provisioning Technology to allow other parties to install Installable Software. You shall be responsible for enabling the
+ applicable license agreements relating to the Installable Software to be presented to, and accepted by, the users of the Provisioning Technology
+ in accordance with the Specification. By using Provisioning Technology in such a manner and making it available in accordance with the
+ Specification, you further acknowledge your agreement to, and the acquisition of all necessary rights to permit the following:
+
+
+ - A series of actions may occur ("Provisioning Process") in which a user may execute the Provisioning Technology
+ on a machine ("Target Machine") with the intent of installing, extending or updating the functionality of an Eclipse-based
+ product.
+ - During the Provisioning Process, the Provisioning Technology may cause third party Installable Software or a portion thereof to be
+ accessed and copied to the Target Machine.
+ - Pursuant to the Specification, you will provide to the user the terms and conditions that govern the use of the Installable
+ Software ("Installable Software Agreement") and such Installable Software Agreement shall be accessed from the Target
+ Machine in accordance with the Specification. Such Installable Software Agreement must inform the user of the terms and conditions that govern
+ the Installable Software and must solicit acceptance by the end user in the manner prescribed in such Installable Software Agreement. Upon such
+ indication of agreement by the user, the provisioning Technology will complete installation of the Installable Software.
+
+
+Cryptography
+
+Content may contain encryption software. The country in which you are currently may have restrictions on the import, possession, and use, and/or re-export to
+ another country, of encryption software. BEFORE using any encryption software, please check the country's laws, regulations and policies concerning the import,
+ possession, or use, and re-export of encryption software, to see if this is permitted.
+
+Java and all Java-based trademarks are trademarks of Oracle Corporation in the United States, other countries, or both.
+
+
+
\ No newline at end of file
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.lfs.feature/pom.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.lfs.feature/pom.xml
new file mode 100644
index 000000000..ef7fd79a9
--- /dev/null
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.lfs.feature/pom.xml
@@ -0,0 +1,77 @@
+
+
+
+
+ 4.0.0
+
+
+ org.eclipse.jgit
+ jgit.tycho.parent
+ 4.3.0-SNAPSHOT
+
+
+ org.eclipse.jgit.feature
+ org.eclipse.jgit.lfs
+ eclipse-feature
+
+ JGit - Optional LFS support
+
+
+
+ org.eclipse.jgit
+ org.eclipse.jgit
+ ${project.version}
+
+
+
+ org.eclipse.jgit
+ org.eclipse.jgit.lfs
+ ${project.version}
+
+
+
+
+
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.repository/category.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.repository/category.xml
index 2186ad982..15d10e6c3 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.repository/category.xml
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.repository/category.xml
@@ -21,6 +21,9 @@
+
+
+
JGit
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.repository/pom.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.repository/pom.xml
index 6e5fd0926..5f21a609d 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.repository/pom.xml
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.repository/pom.xml
@@ -69,6 +69,11 @@
org.eclipse.jgit.http.apache
${project.version}
+
+ org.eclipse.jgit
+ org.eclipse.jgit.lfs
+ ${project.version}
+
org.eclipse.jgit
org.eclipse.jgit.pgm
diff --git a/org.eclipse.jgit.packaging/pom.xml b/org.eclipse.jgit.packaging/pom.xml
index 7f44df875..68efc4650 100644
--- a/org.eclipse.jgit.packaging/pom.xml
+++ b/org.eclipse.jgit.packaging/pom.xml
@@ -1,6 +1,6 @@