diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/PackOutputStream.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/PackOutputStream.java index 68f74641b..2533e906e 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/PackOutputStream.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/PackOutputStream.java @@ -44,6 +44,10 @@ package org.eclipse.jgit.internal.storage.pack; +import static org.eclipse.jgit.lib.Constants.OBJ_OFS_DELTA; +import static org.eclipse.jgit.lib.Constants.OBJ_REF_DELTA; +import static org.eclipse.jgit.lib.Constants.PACK_SIGNATURE; + import java.io.IOException; import java.io.OutputStream; import java.security.MessageDigest; @@ -73,6 +77,8 @@ public final class PackOutputStream extends OutputStream { private long checkCancelAt; + private boolean ofsDelta; + /** * Initialize a pack output stream. *

@@ -132,10 +138,11 @@ public void flush() throws IOException { final void writeFileHeader(int version, long objectCount) throws IOException { - System.arraycopy(Constants.PACK_SIGNATURE, 0, headerBuffer, 0, 4); + System.arraycopy(PACK_SIGNATURE, 0, headerBuffer, 0, 4); NB.encodeInt32(headerBuffer, 4, version); NB.encodeInt32(headerBuffer, 8, (int) objectCount); write(headerBuffer, 0, 12); + ofsDelta = packWriter.isDeltaBaseAsOffset(); } /** @@ -175,43 +182,45 @@ public final void writeObject(ObjectToPack otp) throws IOException { */ public final void writeHeader(ObjectToPack otp, long rawLength) throws IOException { - if (otp.isDeltaRepresentation()) { - if (packWriter.isDeltaBaseAsOffset()) { - ObjectToPack baseInPack = otp.getDeltaBase(); - if (baseInPack != null && baseInPack.isWritten()) { - final long start = count; - int n = encodeTypeSize(Constants.OBJ_OFS_DELTA, rawLength); - write(headerBuffer, 0, n); - - long offsetDiff = start - baseInPack.getOffset(); - n = headerBuffer.length - 1; - headerBuffer[n] = (byte) (offsetDiff & 0x7F); - while ((offsetDiff >>= 7) > 0) - headerBuffer[--n] = (byte) (0x80 | (--offsetDiff & 0x7F)); - write(headerBuffer, n, headerBuffer.length - n); - return; - } - } - - int n = encodeTypeSize(Constants.OBJ_REF_DELTA, rawLength); + ObjectToPack b = otp.getDeltaBase(); + if (b != null && (b.isWritten() & ofsDelta)) { + int n = objectHeader(rawLength, OBJ_OFS_DELTA, headerBuffer); + n = ofsDelta(count - b.getOffset(), headerBuffer, n); + write(headerBuffer, 0, n); + } else if (otp.isDeltaRepresentation()) { + int n = objectHeader(rawLength, OBJ_REF_DELTA, headerBuffer); otp.getDeltaBaseId().copyRawTo(headerBuffer, n); - write(headerBuffer, 0, n + Constants.OBJECT_ID_LENGTH); + write(headerBuffer, 0, n + 20); } else { - int n = encodeTypeSize(otp.getType(), rawLength); + int n = objectHeader(rawLength, otp.getType(), headerBuffer); write(headerBuffer, 0, n); } } - private final int encodeTypeSize(int type, long rawLength) { - long nextLength = rawLength >>> 4; - headerBuffer[0] = (byte) ((nextLength > 0 ? 0x80 : 0x00) | (type << 4) | (rawLength & 0x0F)); - rawLength = nextLength; - int n = 1; - while (rawLength > 0) { - nextLength >>>= 7; - headerBuffer[n++] = (byte) ((nextLength > 0 ? 0x80 : 0x00) | (rawLength & 0x7F)); - rawLength = nextLength; + private static final int objectHeader(long len, int type, byte[] buf) { + byte b = (byte) ((type << 4) | (len & 0x0F)); + int n = 0; + for (len >>>= 4; len != 0; len >>>= 7) { + buf[n++] = (byte) (0x80 | b); + b = (byte) (len & 0x7F); } + buf[n++] = b; + return n; + } + + private static final int ofsDelta(long diff, byte[] buf, int p) { + p += ofsDeltaVarIntLength(diff); + int n = p; + buf[--n] = (byte) (diff & 0x7F); + while ((diff >>>= 7) != 0) + buf[--n] = (byte) (0x80 | (--diff & 0x7F)); + return p; + } + + private static final int ofsDeltaVarIntLength(long v) { + int n = 1; + for (; (v >>>= 7) != 0; n++) + --v; return n; }