View Javadoc
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  
11  package org.eclipse.jgit.pgm.debug;
12  
13  import java.io.ByteArrayInputStream;
14  import java.io.ByteArrayOutputStream;
15  import java.io.IOException;
16  import java.util.Collections;
17  import java.util.zip.InflaterInputStream;
18  
19  import org.eclipse.jgit.errors.MissingObjectException;
20  import org.eclipse.jgit.errors.StoredObjectRepresentationNotAvailableException;
21  import org.eclipse.jgit.internal.storage.pack.BinaryDelta;
22  import org.eclipse.jgit.internal.storage.pack.ObjectReuseAsIs;
23  import org.eclipse.jgit.internal.storage.pack.ObjectToPack;
24  import org.eclipse.jgit.internal.storage.pack.PackOutputStream;
25  import org.eclipse.jgit.internal.storage.pack.PackWriter;
26  import org.eclipse.jgit.internal.storage.pack.StoredObjectRepresentation;
27  import org.eclipse.jgit.lib.NullProgressMonitor;
28  import org.eclipse.jgit.lib.ObjectId;
29  import org.eclipse.jgit.lib.ObjectReader;
30  import org.eclipse.jgit.pgm.Command;
31  import org.eclipse.jgit.pgm.TextBuiltin;
32  import org.eclipse.jgit.revwalk.RevObject;
33  import org.eclipse.jgit.revwalk.RevWalk;
34  import org.eclipse.jgit.util.TemporaryBuffer;
35  import org.kohsuke.args4j.Argument;
36  
37  @Command(usage = "usage_ShowPackDelta")
38  class ShowPackDelta extends TextBuiltin {
39  	@Argument(index = 0)
40  	private ObjectId objectId;
41  
42  	/** {@inheritDoc} */
43  	@Override
44  	protected void run() throws Exception {
45  		ObjectReader reader = db.newObjectReader();
46  		RevObject obj;
47  		try (RevWalk rw = new RevWalk(reader)) {
48  			obj = rw.parseAny(objectId);
49  		}
50  		byte[] delta = getDelta(reader, obj);
51  
52  		// We're crossing our fingers that this will be a delta. Double
53  		// check the size field in the header, it should match.
54  		//
55  		long size = reader.getObjectSize(obj, obj.getType());
56  		try {
57  			if (BinaryDelta.getResultSize(delta) != size)
58  				throw die("Object " + obj.name() + " is not a delta"); //$NON-NLS-1$ //$NON-NLS-2$
59  		} catch (ArrayIndexOutOfBoundsException bad) {
60  			throw die("Object " + obj.name() + " is not a delta", bad); //$NON-NLS-1$ //$NON-NLS-2$
61  		}
62  
63  		outw.println(BinaryDelta.format(delta));
64  	}
65  
66  	private static byte[] getDelta(ObjectReader reader, RevObject obj)
67  			throws IOException, MissingObjectException,
68  			StoredObjectRepresentationNotAvailableException {
69  		ObjectReuseAsIs asis = (ObjectReuseAsIs) reader;
70  		ObjectToPack target = asis.newObjectToPack(obj, obj.getType());
71  
72  		PackWriter pw = new PackWriter(reader) {
73  			@Override
74  			public void select(ObjectToPack otp, StoredObjectRepresentation next) {
75  				otp.select(next);
76  			}
77  		};
78  
79  		ByteArrayOutputStream buf = new ByteArrayOutputStream();
80  		asis.selectObjectRepresentation(pw, NullProgressMonitor.INSTANCE,
81  				Collections.singleton(target));
82  		asis.copyObjectAsIs(new PackOutputStream(NullProgressMonitor.INSTANCE,
83  				buf, pw), target, true);
84  
85  		// At this point the object header has no delta information,
86  		// because it was output as though it were a whole object.
87  		// Skip over the header and inflate.
88  		//
89  		byte[] bufArray = buf.toByteArray();
90  		int ptr = 0;
91  		while ((bufArray[ptr] & 0x80) != 0)
92  			ptr++;
93  		ptr++;
94  
95  		try (TemporaryBuffer.Heap raw = new TemporaryBuffer.Heap(
96  				bufArray.length);
97  				InflaterInputStream inf = new InflaterInputStream(
98  						new ByteArrayInputStream(bufArray, ptr,
99  								bufArray.length))) {
100 			raw.copy(inf);
101 			return raw.toByteArray();
102 		}
103 	}
104 }