ShowPackDelta.java

  1. /*
  2.  * Copyright (C) 2010, Google Inc. and others
  3.  *
  4.  * This program and the accompanying materials are made available under the
  5.  * terms of the Eclipse Distribution License v. 1.0 which is available at
  6.  * https://www.eclipse.org/org/documents/edl-v10.php.
  7.  *
  8.  * SPDX-License-Identifier: BSD-3-Clause
  9.  */

  10. package org.eclipse.jgit.pgm.debug;

  11. import java.io.ByteArrayInputStream;
  12. import java.io.ByteArrayOutputStream;
  13. import java.io.IOException;
  14. import java.util.Collections;
  15. import java.util.zip.InflaterInputStream;

  16. import org.eclipse.jgit.errors.MissingObjectException;
  17. import org.eclipse.jgit.errors.StoredObjectRepresentationNotAvailableException;
  18. import org.eclipse.jgit.internal.storage.pack.BinaryDelta;
  19. import org.eclipse.jgit.internal.storage.pack.ObjectReuseAsIs;
  20. import org.eclipse.jgit.internal.storage.pack.ObjectToPack;
  21. import org.eclipse.jgit.internal.storage.pack.PackOutputStream;
  22. import org.eclipse.jgit.internal.storage.pack.PackWriter;
  23. import org.eclipse.jgit.internal.storage.pack.StoredObjectRepresentation;
  24. import org.eclipse.jgit.lib.NullProgressMonitor;
  25. import org.eclipse.jgit.lib.ObjectId;
  26. import org.eclipse.jgit.lib.ObjectReader;
  27. import org.eclipse.jgit.pgm.Command;
  28. import org.eclipse.jgit.pgm.TextBuiltin;
  29. import org.eclipse.jgit.revwalk.RevObject;
  30. import org.eclipse.jgit.revwalk.RevWalk;
  31. import org.eclipse.jgit.util.TemporaryBuffer;
  32. import org.kohsuke.args4j.Argument;

  33. @Command(usage = "usage_ShowPackDelta")
  34. class ShowPackDelta extends TextBuiltin {
  35.     @Argument(index = 0)
  36.     private ObjectId objectId;

  37.     /** {@inheritDoc} */
  38.     @Override
  39.     protected void run() throws Exception {
  40.         ObjectReader reader = db.newObjectReader();
  41.         RevObject obj;
  42.         try (RevWalk rw = new RevWalk(reader)) {
  43.             obj = rw.parseAny(objectId);
  44.         }
  45.         byte[] delta = getDelta(reader, obj);

  46.         // We're crossing our fingers that this will be a delta. Double
  47.         // check the size field in the header, it should match.
  48.         //
  49.         long size = reader.getObjectSize(obj, obj.getType());
  50.         try {
  51.             if (BinaryDelta.getResultSize(delta) != size)
  52.                 throw die("Object " + obj.name() + " is not a delta"); //$NON-NLS-1$ //$NON-NLS-2$
  53.         } catch (ArrayIndexOutOfBoundsException bad) {
  54.             throw die("Object " + obj.name() + " is not a delta", bad); //$NON-NLS-1$ //$NON-NLS-2$
  55.         }

  56.         outw.println(BinaryDelta.format(delta));
  57.     }

  58.     private static byte[] getDelta(ObjectReader reader, RevObject obj)
  59.             throws IOException, MissingObjectException,
  60.             StoredObjectRepresentationNotAvailableException {
  61.         ObjectReuseAsIs asis = (ObjectReuseAsIs) reader;
  62.         ObjectToPack target = asis.newObjectToPack(obj, obj.getType());

  63.         PackWriter pw = new PackWriter(reader) {
  64.             @Override
  65.             public void select(ObjectToPack otp, StoredObjectRepresentation next) {
  66.                 otp.select(next);
  67.             }
  68.         };

  69.         ByteArrayOutputStream buf = new ByteArrayOutputStream();
  70.         asis.selectObjectRepresentation(pw, NullProgressMonitor.INSTANCE,
  71.                 Collections.singleton(target));
  72.         asis.copyObjectAsIs(new PackOutputStream(NullProgressMonitor.INSTANCE,
  73.                 buf, pw), target, true);

  74.         // At this point the object header has no delta information,
  75.         // because it was output as though it were a whole object.
  76.         // Skip over the header and inflate.
  77.         //
  78.         byte[] bufArray = buf.toByteArray();
  79.         int ptr = 0;
  80.         while ((bufArray[ptr] & 0x80) != 0)
  81.             ptr++;
  82.         ptr++;

  83.         try (TemporaryBuffer.Heap raw = new TemporaryBuffer.Heap(
  84.                 bufArray.length);
  85.                 InflaterInputStream inf = new InflaterInputStream(
  86.                         new ByteArrayInputStream(bufArray, ptr,
  87.                                 bufArray.length))) {
  88.             raw.copy(inf);
  89.             return raw.toByteArray();
  90.         }
  91.     }
  92. }