View Javadoc
1   /*
2    * Copyright (C) 2008-2011, Google Inc.
3    * Copyright (C) 2007-2008, Robin Rosenberg <robin.rosenberg@dewire.com>
4    * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org>
5    * and other copyright owners as documented in the project's IP log.
6    *
7    * This program and the accompanying materials are made available
8    * under the terms of the Eclipse Distribution License v1.0 which
9    * accompanies this distribution, is reproduced below, and is
10   * available at http://www.eclipse.org/org/documents/edl-v10.php
11   *
12   * All rights reserved.
13   *
14   * Redistribution and use in source and binary forms, with or
15   * without modification, are permitted provided that the following
16   * conditions are met:
17   *
18   * - Redistributions of source code must retain the above copyright
19   *   notice, this list of conditions and the following disclaimer.
20   *
21   * - Redistributions in binary form must reproduce the above
22   *   copyright notice, this list of conditions and the following
23   *   disclaimer in the documentation and/or other materials provided
24   *   with the distribution.
25   *
26   * - Neither the name of the Eclipse Foundation, Inc. nor the
27   *   names of its contributors may be used to endorse or promote
28   *   products derived from this software without specific prior
29   *   written permission.
30   *
31   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
32   * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
33   * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
34   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
35   * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
36   * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
37   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
38   * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
39   * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
40   * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
41   * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
42   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
43   * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
44   */
45  
46  package org.eclipse.jgit.transport;
47  
48  import java.io.EOFException;
49  import java.io.IOException;
50  import java.io.InputStream;
51  import java.security.MessageDigest;
52  import java.text.MessageFormat;
53  import java.util.ArrayList;
54  import java.util.Arrays;
55  import java.util.Comparator;
56  import java.util.List;
57  import java.util.concurrent.TimeUnit;
58  import java.util.zip.DataFormatException;
59  import java.util.zip.Inflater;
60  
61  import org.eclipse.jgit.errors.CorruptObjectException;
62  import org.eclipse.jgit.errors.MissingObjectException;
63  import org.eclipse.jgit.errors.TooLargeObjectInPackException;
64  import org.eclipse.jgit.internal.JGitText;
65  import org.eclipse.jgit.internal.storage.file.PackLock;
66  import org.eclipse.jgit.internal.storage.pack.BinaryDelta;
67  import org.eclipse.jgit.lib.AnyObjectId;
68  import org.eclipse.jgit.lib.BatchingProgressMonitor;
69  import org.eclipse.jgit.lib.BlobObjectChecker;
70  import org.eclipse.jgit.lib.Constants;
71  import org.eclipse.jgit.lib.InflaterCache;
72  import org.eclipse.jgit.lib.MutableObjectId;
73  import org.eclipse.jgit.lib.NullProgressMonitor;
74  import org.eclipse.jgit.lib.ObjectChecker;
75  import org.eclipse.jgit.lib.ObjectDatabase;
76  import org.eclipse.jgit.lib.ObjectId;
77  import org.eclipse.jgit.lib.ObjectIdOwnerMap;
78  import org.eclipse.jgit.lib.ObjectIdSubclassMap;
79  import org.eclipse.jgit.lib.ObjectLoader;
80  import org.eclipse.jgit.lib.ObjectReader;
81  import org.eclipse.jgit.lib.ObjectStream;
82  import org.eclipse.jgit.lib.ProgressMonitor;
83  import org.eclipse.jgit.util.BlockList;
84  import org.eclipse.jgit.util.IO;
85  import org.eclipse.jgit.util.LongMap;
86  import org.eclipse.jgit.util.NB;
87  import org.eclipse.jgit.util.sha1.SHA1;
88  
89  /**
90   * Parses a pack stream and imports it for an
91   * {@link org.eclipse.jgit.lib.ObjectInserter}.
92   * <p>
93   * Applications can acquire an instance of a parser from ObjectInserter's
94   * {@link org.eclipse.jgit.lib.ObjectInserter#newPackParser(InputStream)}
95   * method.
96   * <p>
97   * Implementations of {@link org.eclipse.jgit.lib.ObjectInserter} should
98   * subclass this type and provide their own logic for the various {@code on*()}
99   * event methods declared to be abstract.
100  */
101 public abstract class PackParser {
102 	/** Size of the internal stream buffer. */
103 	private static final int BUFFER_SIZE = 8192;
104 
105 	/** Location data is being obtained from. */
106 	public static enum Source {
107 		/** Data is read from the incoming stream. */
108 		INPUT,
109 
110 		/** Data is read back from the database's buffers. */
111 		DATABASE;
112 	}
113 
114 	/** Object database used for loading existing objects. */
115 	private final ObjectDatabase objectDatabase;
116 
117 	private InflaterStream inflater;
118 
119 	private byte[] tempBuffer;
120 
121 	private byte[] hdrBuf;
122 
123 	private final SHA1 objectHasher = SHA1.newInstance();
124 	private final MutableObjectId tempObjectId;
125 
126 	private InputStream in;
127 
128 	byte[] buf;
129 
130 	/** Position in the input stream of {@code buf[0]}. */
131 	private long bBase;
132 
133 	private int bOffset;
134 
135 	int bAvail;
136 
137 	private ObjectChecker objCheck;
138 
139 	private boolean allowThin;
140 
141 	private boolean checkObjectCollisions;
142 
143 	private boolean needBaseObjectIds;
144 
145 	private boolean checkEofAfterPackFooter;
146 
147 	private boolean expectDataAfterPackFooter;
148 
149 	private long expectedObjectCount;
150 
151 	private PackedObjectInfo[] entries;
152 
153 	/**
154 	 * Every object contained within the incoming pack.
155 	 * <p>
156 	 * This is a subset of {@link #entries}, as thin packs can add additional
157 	 * objects to {@code entries} by copying already existing objects from the
158 	 * repository onto the end of the thin pack to make it self-contained.
159 	 */
160 	private ObjectIdSubclassMap<ObjectId> newObjectIds;
161 
162 	private int deltaCount;
163 
164 	private int entryCount;
165 
166 	private ObjectIdOwnerMap<DeltaChain> baseById;
167 
168 	/**
169 	 * Objects referenced by their name from deltas, that aren't in this pack.
170 	 * <p>
171 	 * This is the set of objects that were copied onto the end of this pack to
172 	 * make it complete. These objects were not transmitted by the remote peer,
173 	 * but instead were assumed to already exist in the local repository.
174 	 */
175 	private ObjectIdSubclassMap<ObjectId> baseObjectIds;
176 
177 	private LongMap<UnresolvedDelta> baseByPos;
178 
179 	/** Objects need to be double-checked for collision after indexing. */
180 	private BlockList<PackedObjectInfo> collisionCheckObjs;
181 
182 	private MessageDigest packDigest;
183 
184 	private ObjectReader readCurs;
185 
186 	/** Message to protect the pack data from garbage collection. */
187 	private String lockMessage;
188 
189 	/** Git object size limit */
190 	private long maxObjectSizeLimit;
191 
192 	private final ReceivedPackStatistics.Builder stats =
193 			new ReceivedPackStatistics.Builder();
194 
195 	/**
196 	 * Initialize a pack parser.
197 	 *
198 	 * @param odb
199 	 *            database the parser will write its objects into.
200 	 * @param src
201 	 *            the stream the parser will read.
202 	 */
203 	protected PackParser(final ObjectDatabase odb, final InputStream src) {
204 		objectDatabase = odb.newCachedDatabase();
205 		in = src;
206 
207 		inflater = new InflaterStream();
208 		readCurs = objectDatabase.newReader();
209 		buf = new byte[BUFFER_SIZE];
210 		tempBuffer = new byte[BUFFER_SIZE];
211 		hdrBuf = new byte[64];
212 		tempObjectId = new MutableObjectId();
213 		packDigest = Constants.newMessageDigest();
214 		checkObjectCollisions = true;
215 	}
216 
217 	/**
218 	 * Whether a thin pack (missing base objects) is permitted.
219 	 *
220 	 * @return {@code true} if a thin pack (missing base objects) is permitted.
221 	 */
222 	public boolean isAllowThin() {
223 		return allowThin;
224 	}
225 
226 	/**
227 	 * Configure this index pack instance to allow a thin pack.
228 	 * <p>
229 	 * Thin packs are sometimes used during network transfers to allow a delta
230 	 * to be sent without a base object. Such packs are not permitted on disk.
231 	 *
232 	 * @param allow
233 	 *            true to enable a thin pack.
234 	 */
235 	public void setAllowThin(final boolean allow) {
236 		allowThin = allow;
237 	}
238 
239 	/**
240 	 * Whether received objects are verified to prevent collisions.
241 	 *
242 	 * @return if true received objects are verified to prevent collisions.
243 	 * @since 4.1
244 	 */
245 	protected boolean isCheckObjectCollisions() {
246 		return checkObjectCollisions;
247 	}
248 
249 	/**
250 	 * Enable checking for collisions with existing objects.
251 	 * <p>
252 	 * By default PackParser looks for each received object in the repository.
253 	 * If the object already exists, the existing object is compared
254 	 * byte-for-byte with the newly received copy to ensure they are identical.
255 	 * The receive is aborted with an exception if any byte differs. This check
256 	 * is necessary to prevent an evil attacker from supplying a replacement
257 	 * object into this repository in the event that a discovery enabling SHA-1
258 	 * collisions is made.
259 	 * <p>
260 	 * This check may be very costly to perform, and some repositories may have
261 	 * other ways to segregate newly received object data. The check is enabled
262 	 * by default, but can be explicitly disabled if the implementation can
263 	 * provide the same guarantee, or is willing to accept the risks associated
264 	 * with bypassing the check.
265 	 *
266 	 * @param check
267 	 *            true to enable collision checking (strongly encouraged).
268 	 * @since 4.1
269 	 */
270 	protected void setCheckObjectCollisions(boolean check) {
271 		checkObjectCollisions = check;
272 	}
273 
274 	/**
275 	 * Configure this index pack instance to keep track of new objects.
276 	 * <p>
277 	 * By default an index pack doesn't save the new objects that were created
278 	 * when it was instantiated. Setting this flag to {@code true} allows the
279 	 * caller to use {@link #getNewObjectIds()} to retrieve that list.
280 	 *
281 	 * @param b
282 	 *            {@code true} to enable keeping track of new objects.
283 	 */
284 	public void setNeedNewObjectIds(boolean b) {
285 		if (b)
286 			newObjectIds = new ObjectIdSubclassMap<>();
287 		else
288 			newObjectIds = null;
289 	}
290 
291 	private boolean needNewObjectIds() {
292 		return newObjectIds != null;
293 	}
294 
295 	/**
296 	 * Configure this index pack instance to keep track of the objects assumed
297 	 * for delta bases.
298 	 * <p>
299 	 * By default an index pack doesn't save the objects that were used as delta
300 	 * bases. Setting this flag to {@code true} will allow the caller to use
301 	 * {@link #getBaseObjectIds()} to retrieve that list.
302 	 *
303 	 * @param b
304 	 *            {@code true} to enable keeping track of delta bases.
305 	 */
306 	public void setNeedBaseObjectIds(boolean b) {
307 		this.needBaseObjectIds = b;
308 	}
309 
310 	/**
311 	 * Whether the EOF should be read from the input after the footer.
312 	 *
313 	 * @return true if the EOF should be read from the input after the footer.
314 	 */
315 	public boolean isCheckEofAfterPackFooter() {
316 		return checkEofAfterPackFooter;
317 	}
318 
319 	/**
320 	 * Ensure EOF is read from the input stream after the footer.
321 	 *
322 	 * @param b
323 	 *            true if the EOF should be read; false if it is not checked.
324 	 */
325 	public void setCheckEofAfterPackFooter(boolean b) {
326 		checkEofAfterPackFooter = b;
327 	}
328 
329 	/**
330 	 * Whether there is data expected after the pack footer.
331 	 *
332 	 * @return true if there is data expected after the pack footer.
333 	 */
334 	public boolean isExpectDataAfterPackFooter() {
335 		return expectDataAfterPackFooter;
336 	}
337 
338 	/**
339 	 * Set if there is additional data in InputStream after pack.
340 	 *
341 	 * @param e
342 	 *            true if there is additional data in InputStream after pack.
343 	 *            This requires the InputStream to support the mark and reset
344 	 *            functions.
345 	 */
346 	public void setExpectDataAfterPackFooter(boolean e) {
347 		expectDataAfterPackFooter = e;
348 	}
349 
350 	/**
351 	 * Get the new objects that were sent by the user
352 	 *
353 	 * @return the new objects that were sent by the user
354 	 */
355 	public ObjectIdSubclassMap<ObjectId> getNewObjectIds() {
356 		if (newObjectIds != null)
357 			return newObjectIds;
358 		return new ObjectIdSubclassMap<>();
359 	}
360 
361 	/**
362 	 * Get set of objects the incoming pack assumed for delta purposes
363 	 *
364 	 * @return set of objects the incoming pack assumed for delta purposes
365 	 */
366 	public ObjectIdSubclassMap<ObjectId> getBaseObjectIds() {
367 		if (baseObjectIds != null)
368 			return baseObjectIds;
369 		return new ObjectIdSubclassMap<>();
370 	}
371 
372 	/**
373 	 * Configure the checker used to validate received objects.
374 	 * <p>
375 	 * Usually object checking isn't necessary, as Git implementations only
376 	 * create valid objects in pack files. However, additional checking may be
377 	 * useful if processing data from an untrusted source.
378 	 *
379 	 * @param oc
380 	 *            the checker instance; null to disable object checking.
381 	 */
382 	public void setObjectChecker(final ObjectChecker oc) {
383 		objCheck = oc;
384 	}
385 
386 	/**
387 	 * Configure the checker used to validate received objects.
388 	 * <p>
389 	 * Usually object checking isn't necessary, as Git implementations only
390 	 * create valid objects in pack files. However, additional checking may be
391 	 * useful if processing data from an untrusted source.
392 	 * <p>
393 	 * This is shorthand for:
394 	 *
395 	 * <pre>
396 	 * setObjectChecker(on ? new ObjectChecker() : null);
397 	 * </pre>
398 	 *
399 	 * @param on
400 	 *            true to enable the default checker; false to disable it.
401 	 */
402 	public void setObjectChecking(final boolean on) {
403 		setObjectChecker(on ? new ObjectChecker() : null);
404 	}
405 
406 	/**
407 	 * Get the message to record with the pack lock.
408 	 *
409 	 * @return the message to record with the pack lock.
410 	 */
411 	public String getLockMessage() {
412 		return lockMessage;
413 	}
414 
415 	/**
416 	 * Set the lock message for the incoming pack data.
417 	 *
418 	 * @param msg
419 	 *            if not null, the message to associate with the incoming data
420 	 *            while it is locked to prevent garbage collection.
421 	 */
422 	public void setLockMessage(String msg) {
423 		lockMessage = msg;
424 	}
425 
426 	/**
427 	 * Set the maximum allowed Git object size.
428 	 * <p>
429 	 * If an object is larger than the given size the pack-parsing will throw an
430 	 * exception aborting the parsing.
431 	 *
432 	 * @param limit
433 	 *            the Git object size limit. If zero then there is not limit.
434 	 */
435 	public void setMaxObjectSizeLimit(long limit) {
436 		maxObjectSizeLimit = limit;
437 	}
438 
439 	/**
440 	 * Get the number of objects in the stream.
441 	 * <p>
442 	 * The object count is only available after {@link #parse(ProgressMonitor)}
443 	 * has returned. The count may have been increased if the stream was a thin
444 	 * pack, and missing bases objects were appending onto it by the subclass.
445 	 *
446 	 * @return number of objects parsed out of the stream.
447 	 */
448 	public int getObjectCount() {
449 		return entryCount;
450 	}
451 
452 	/**
453 	 * Get the information about the requested object.
454 	 * <p>
455 	 * The object information is only available after
456 	 * {@link #parse(ProgressMonitor)} has returned.
457 	 *
458 	 * @param nth
459 	 *            index of the object in the stream. Must be between 0 and
460 	 *            {@link #getObjectCount()}-1.
461 	 * @return the object information.
462 	 */
463 	public PackedObjectInfo getObject(int nth) {
464 		return entries[nth];
465 	}
466 
467 	/**
468 	 * Get all of the objects, sorted by their name.
469 	 * <p>
470 	 * The object information is only available after
471 	 * {@link #parse(ProgressMonitor)} has returned.
472 	 * <p>
473 	 * To maintain lower memory usage and good runtime performance, this method
474 	 * sorts the objects in-place and therefore impacts the ordering presented
475 	 * by {@link #getObject(int)}.
476 	 *
477 	 * @param cmp
478 	 *            comparison function, if null objects are stored by ObjectId.
479 	 * @return sorted list of objects in this pack stream.
480 	 */
481 	public List<PackedObjectInfo> getSortedObjectList(
482 			Comparator<PackedObjectInfo> cmp) {
483 		Arrays.sort(entries, 0, entryCount, cmp);
484 		List<PackedObjectInfo> list = Arrays.asList(entries);
485 		if (entryCount < entries.length)
486 			list = list.subList(0, entryCount);
487 		return list;
488 	}
489 
490 	/**
491 	 * Get the size of the newly created pack.
492 	 * <p>
493 	 * This will also include the pack index size if an index was created. This
494 	 * method should only be called after pack parsing is finished.
495 	 *
496 	 * @return the pack size (including the index size) or -1 if the size cannot
497 	 *         be determined
498 	 * @since 3.3
499 	 */
500 	public long getPackSize() {
501 		return -1;
502 	}
503 
504 	/**
505 	 * Returns the statistics of the parsed pack.
506 	 * <p>
507 	 * This should only be called after pack parsing is finished.
508 	 *
509 	 * @return {@link org.eclipse.jgit.transport.ReceivedPackStatistics}
510 	 * @since 4.6
511 	 */
512 	public ReceivedPackStatistics getReceivedPackStatistics() {
513 		return stats.build();
514 	}
515 
516 	/**
517 	 * Parse the pack stream.
518 	 *
519 	 * @param progress
520 	 *            callback to provide progress feedback during parsing. If null,
521 	 *            {@link org.eclipse.jgit.lib.NullProgressMonitor} will be used.
522 	 * @return the pack lock, if one was requested by setting
523 	 *         {@link #setLockMessage(String)}.
524 	 * @throws java.io.IOException
525 	 *             the stream is malformed, or contains corrupt objects.
526 	 * @since 3.0
527 	 */
528 	public final PackLock parse(ProgressMonitor progress) throws IOException {
529 		return parse(progress, progress);
530 	}
531 
532 	/**
533 	 * Parse the pack stream.
534 	 *
535 	 * @param receiving
536 	 *            receives progress feedback during the initial receiving
537 	 *            objects phase. If null,
538 	 *            {@link org.eclipse.jgit.lib.NullProgressMonitor} will be used.
539 	 * @param resolving
540 	 *            receives progress feedback during the resolving objects phase.
541 	 * @return the pack lock, if one was requested by setting
542 	 *         {@link #setLockMessage(String)}.
543 	 * @throws java.io.IOException
544 	 *             the stream is malformed, or contains corrupt objects.
545 	 * @since 3.0
546 	 */
547 	public PackLock parse(ProgressMonitor receiving, ProgressMonitor resolving)
548 			throws IOException {
549 		if (receiving == null)
550 			receiving = NullProgressMonitor.INSTANCE;
551 		if (resolving == null)
552 			resolving = NullProgressMonitor.INSTANCE;
553 
554 		if (receiving == resolving)
555 			receiving.start(2 /* tasks */);
556 		try {
557 			readPackHeader();
558 
559 			entries = new PackedObjectInfo[(int) expectedObjectCount];
560 			baseById = new ObjectIdOwnerMap<>();
561 			baseByPos = new LongMap<>();
562 			collisionCheckObjs = new BlockList<>();
563 
564 			receiving.beginTask(JGitText.get().receivingObjects,
565 					(int) expectedObjectCount);
566 			try {
567 				for (int done = 0; done < expectedObjectCount; done++) {
568 					indexOneObject();
569 					receiving.update(1);
570 					if (receiving.isCancelled())
571 						throw new IOException(JGitText.get().downloadCancelled);
572 				}
573 				readPackFooter();
574 				endInput();
575 			} finally {
576 				receiving.endTask();
577 			}
578 
579 			if (!collisionCheckObjs.isEmpty()) {
580 				checkObjectCollision();
581 			}
582 
583 			if (deltaCount > 0) {
584 				processDeltas(resolving);
585 			}
586 
587 			packDigest = null;
588 			baseById = null;
589 			baseByPos = null;
590 		} finally {
591 			try {
592 				if (readCurs != null)
593 					readCurs.close();
594 			} finally {
595 				readCurs = null;
596 			}
597 
598 			try {
599 				inflater.release();
600 			} finally {
601 				inflater = null;
602 			}
603 		}
604 		return null; // By default there is no locking.
605 	}
606 
607 	private void processDeltas(ProgressMonitor resolving) throws IOException {
608 		if (resolving instanceof BatchingProgressMonitor) {
609 			((BatchingProgressMonitor) resolving).setDelayStart(1000,
610 					TimeUnit.MILLISECONDS);
611 		}
612 		resolving.beginTask(JGitText.get().resolvingDeltas, deltaCount);
613 		resolveDeltas(resolving);
614 		if (entryCount < expectedObjectCount) {
615 			if (!isAllowThin()) {
616 				throw new IOException(MessageFormat.format(
617 						JGitText.get().packHasUnresolvedDeltas,
618 						Long.valueOf(expectedObjectCount - entryCount)));
619 			}
620 
621 			resolveDeltasWithExternalBases(resolving);
622 
623 			if (entryCount < expectedObjectCount) {
624 				throw new IOException(MessageFormat.format(
625 						JGitText.get().packHasUnresolvedDeltas,
626 						Long.valueOf(expectedObjectCount - entryCount)));
627 			}
628 		}
629 		resolving.endTask();
630 	}
631 
632 	private void resolveDeltas(final ProgressMonitor progress)
633 			throws IOException {
634 		final int last = entryCount;
635 		for (int i = 0; i < last; i++) {
636 			resolveDeltas(entries[i], progress);
637 			if (progress.isCancelled())
638 				throw new IOException(
639 						JGitText.get().downloadCancelledDuringIndexing);
640 		}
641 	}
642 
643 	private void resolveDeltas(final PackedObjectInfo oe,
644 			ProgressMonitor progress) throws IOException {
645 		UnresolvedDelta children = firstChildOf(oe);
646 		if (children == null)
647 			return;
648 
649 		DeltaVisit visit = new DeltaVisit();
650 		visit.nextChild = children;
651 
652 		ObjectTypeAndSize info = openDatabase(oe, new ObjectTypeAndSize());
653 		switch (info.type) {
654 		case Constants.OBJ_COMMIT:
655 		case Constants.OBJ_TREE:
656 		case Constants.OBJ_BLOB:
657 		case Constants.OBJ_TAG:
658 			visit.data = inflateAndReturn(Source.DATABASE, info.size);
659 			visit.id = oe;
660 			break;
661 		default:
662 			throw new IOException(MessageFormat.format(
663 					JGitText.get().unknownObjectType,
664 					Integer.valueOf(info.type)));
665 		}
666 
667 		if (!checkCRC(oe.getCRC())) {
668 			throw new IOException(MessageFormat.format(
669 					JGitText.get().corruptionDetectedReReadingAt,
670 					Long.valueOf(oe.getOffset())));
671 		}
672 
673 		resolveDeltas(visit.next(), info.type, info, progress);
674 	}
675 
676 	private void resolveDeltas(DeltaVisit visit, final int type,
677 			ObjectTypeAndSize info, ProgressMonitor progress)
678 			throws IOException {
679 		stats.addDeltaObject(type);
680 		do {
681 			progress.update(1);
682 			info = openDatabase(visit.delta, info);
683 			switch (info.type) {
684 			case Constants.OBJ_OFS_DELTA:
685 			case Constants.OBJ_REF_DELTA:
686 				break;
687 
688 			default:
689 				throw new IOException(MessageFormat.format(
690 						JGitText.get().unknownObjectType,
691 						Integer.valueOf(info.type)));
692 			}
693 
694 			byte[] delta = inflateAndReturn(Source.DATABASE, info.size);
695 			checkIfTooLarge(type, BinaryDelta.getResultSize(delta));
696 
697 			visit.data = BinaryDelta.apply(visit.parent.data, delta);
698 			delta = null;
699 
700 			if (!checkCRC(visit.delta.crc))
701 				throw new IOException(MessageFormat.format(
702 						JGitText.get().corruptionDetectedReReadingAt,
703 						Long.valueOf(visit.delta.position)));
704 
705 			SHA1 objectDigest = objectHasher.reset();
706 			objectDigest.update(Constants.encodedTypeString(type));
707 			objectDigest.update((byte) ' ');
708 			objectDigest.update(Constants.encodeASCII(visit.data.length));
709 			objectDigest.update((byte) 0);
710 			objectDigest.update(visit.data);
711 			objectDigest.digest(tempObjectId);
712 
713 			verifySafeObject(tempObjectId, type, visit.data);
714 			if (isCheckObjectCollisions() && readCurs.has(tempObjectId)) {
715 				checkObjectCollision(tempObjectId, type, visit.data);
716 			}
717 
718 			PackedObjectInfo oe;
719 			oe = newInfo(tempObjectId, visit.delta, visit.parent.id);
720 			oe.setOffset(visit.delta.position);
721 			oe.setType(type);
722 			onInflatedObjectData(oe, type, visit.data);
723 			addObjectAndTrack(oe);
724 			visit.id = oe;
725 
726 			visit.nextChild = firstChildOf(oe);
727 			visit = visit.next();
728 		} while (visit != null);
729 	}
730 
731 	private final void checkIfTooLarge(int typeCode, long size)
732 			throws IOException {
733 		if (0 < maxObjectSizeLimit && maxObjectSizeLimit < size) {
734 			switch (typeCode) {
735 			case Constants.OBJ_COMMIT:
736 			case Constants.OBJ_TREE:
737 			case Constants.OBJ_BLOB:
738 			case Constants.OBJ_TAG:
739 				throw new TooLargeObjectInPackException(size, maxObjectSizeLimit);
740 
741 			case Constants.OBJ_OFS_DELTA:
742 			case Constants.OBJ_REF_DELTA:
743 				throw new TooLargeObjectInPackException(size, maxObjectSizeLimit);
744 
745 			default:
746 				throw new IOException(MessageFormat.format(
747 						JGitText.get().unknownObjectType,
748 						Integer.valueOf(typeCode)));
749 			}
750 		}
751 		if (size > Integer.MAX_VALUE - 8) {
752 			throw new TooLargeObjectInPackException(size, Integer.MAX_VALUE - 8);
753 		}
754 	}
755 
756 	/**
757 	 * Read the header of the current object.
758 	 * <p>
759 	 * After the header has been parsed, this method automatically invokes
760 	 * {@link #onObjectHeader(Source, byte[], int, int)} to allow the
761 	 * implementation to update its internal checksums for the bytes read.
762 	 * <p>
763 	 * When this method returns the database will be positioned on the first
764 	 * byte of the deflated data stream.
765 	 *
766 	 * @param info
767 	 *            the info object to populate.
768 	 * @return {@code info}, after populating.
769 	 * @throws java.io.IOException
770 	 *             the size cannot be read.
771 	 */
772 	protected ObjectTypeAndSize readObjectHeader(ObjectTypeAndSize info)
773 			throws IOException {
774 		int hdrPtr = 0;
775 		int c = readFrom(Source.DATABASE);
776 		hdrBuf[hdrPtr++] = (byte) c;
777 
778 		info.type = (c >> 4) & 7;
779 		long sz = c & 15;
780 		int shift = 4;
781 		while ((c & 0x80) != 0) {
782 			c = readFrom(Source.DATABASE);
783 			hdrBuf[hdrPtr++] = (byte) c;
784 			sz += ((long) (c & 0x7f)) << shift;
785 			shift += 7;
786 		}
787 		info.size = sz;
788 
789 		switch (info.type) {
790 		case Constants.OBJ_COMMIT:
791 		case Constants.OBJ_TREE:
792 		case Constants.OBJ_BLOB:
793 		case Constants.OBJ_TAG:
794 			onObjectHeader(Source.DATABASE, hdrBuf, 0, hdrPtr);
795 			break;
796 
797 		case Constants.OBJ_OFS_DELTA:
798 			c = readFrom(Source.DATABASE);
799 			hdrBuf[hdrPtr++] = (byte) c;
800 			while ((c & 128) != 0) {
801 				c = readFrom(Source.DATABASE);
802 				hdrBuf[hdrPtr++] = (byte) c;
803 			}
804 			onObjectHeader(Source.DATABASE, hdrBuf, 0, hdrPtr);
805 			break;
806 
807 		case Constants.OBJ_REF_DELTA:
808 			System.arraycopy(buf, fill(Source.DATABASE, 20), hdrBuf, hdrPtr, 20);
809 			hdrPtr += 20;
810 			use(20);
811 			onObjectHeader(Source.DATABASE, hdrBuf, 0, hdrPtr);
812 			break;
813 
814 		default:
815 			throw new IOException(MessageFormat.format(
816 					JGitText.get().unknownObjectType,
817 					Integer.valueOf(info.type)));
818 		}
819 		return info;
820 	}
821 
822 	private UnresolvedDelta removeBaseById(final AnyObjectId id) {
823 		final DeltaChain d = baseById.get(id);
824 		return d != null ? d.remove() : null;
825 	}
826 
827 	private static UnresolvedDelta reverse(UnresolvedDelta c) {
828 		UnresolvedDelta tail = null;
829 		while (c != null) {
830 			final UnresolvedDelta n = c.next;
831 			c.next = tail;
832 			tail = c;
833 			c = n;
834 		}
835 		return tail;
836 	}
837 
838 	private UnresolvedDelta firstChildOf(PackedObjectInfo oe) {
839 		UnresolvedDelta a = reverse(removeBaseById(oe));
840 		UnresolvedDelta b = reverse(baseByPos.remove(oe.getOffset()));
841 
842 		if (a == null)
843 			return b;
844 		if (b == null)
845 			return a;
846 
847 		UnresolvedDelta first = null;
848 		UnresolvedDelta last = null;
849 		while (a != null || b != null) {
850 			UnresolvedDelta curr;
851 			if (b == null || (a != null && a.position < b.position)) {
852 				curr = a;
853 				a = a.next;
854 			} else {
855 				curr = b;
856 				b = b.next;
857 			}
858 			if (last != null)
859 				last.next = curr;
860 			else
861 				first = curr;
862 			last = curr;
863 			curr.next = null;
864 		}
865 		return first;
866 	}
867 
868 	private void resolveDeltasWithExternalBases(final ProgressMonitor progress)
869 			throws IOException {
870 		growEntries(baseById.size());
871 
872 		if (needBaseObjectIds)
873 			baseObjectIds = new ObjectIdSubclassMap<>();
874 
875 		final List<DeltaChain> missing = new ArrayList<>(64);
876 		for (final DeltaChain baseId : baseById) {
877 			if (baseId.head == null)
878 				continue;
879 
880 			if (needBaseObjectIds)
881 				baseObjectIds.add(baseId);
882 
883 			final ObjectLoader ldr;
884 			try {
885 				ldr = readCurs.open(baseId);
886 			} catch (MissingObjectException notFound) {
887 				missing.add(baseId);
888 				continue;
889 			}
890 
891 			final DeltaVisit visit = new DeltaVisit();
892 			visit.data = ldr.getCachedBytes(Integer.MAX_VALUE);
893 			visit.id = baseId;
894 			final int typeCode = ldr.getType();
895 			final PackedObjectInfo oe = newInfo(baseId, null, null);
896 			oe.setType(typeCode);
897 			if (onAppendBase(typeCode, visit.data, oe))
898 				entries[entryCount++] = oe;
899 			visit.nextChild = firstChildOf(oe);
900 			resolveDeltas(visit.next(), typeCode,
901 					new ObjectTypeAndSize(), progress);
902 
903 			if (progress.isCancelled())
904 				throw new IOException(
905 						JGitText.get().downloadCancelledDuringIndexing);
906 		}
907 
908 		for (final DeltaChain base : missing) {
909 			if (base.head != null)
910 				throw new MissingObjectException(base, "delta base"); //$NON-NLS-1$
911 		}
912 
913 		onEndThinPack();
914 	}
915 
916 	private void growEntries(int extraObjects) {
917 		final PackedObjectInfo[] ne;
918 
919 		ne = new PackedObjectInfo[(int) expectedObjectCount + extraObjects];
920 		System.arraycopy(entries, 0, ne, 0, entryCount);
921 		entries = ne;
922 	}
923 
924 	private void readPackHeader() throws IOException {
925 		if (expectDataAfterPackFooter) {
926 			if (!in.markSupported())
927 				throw new IOException(
928 						JGitText.get().inputStreamMustSupportMark);
929 			in.mark(buf.length);
930 		}
931 
932 		final int hdrln = Constants.PACK_SIGNATURE.length + 4 + 4;
933 		final int p = fill(Source.INPUT, hdrln);
934 		for (int k = 0; k < Constants.PACK_SIGNATURE.length; k++)
935 			if (buf[p + k] != Constants.PACK_SIGNATURE[k])
936 				throw new IOException(JGitText.get().notAPACKFile);
937 
938 		final long vers = NB.decodeUInt32(buf, p + 4);
939 		if (vers != 2 && vers != 3)
940 			throw new IOException(MessageFormat.format(
941 					JGitText.get().unsupportedPackVersion, Long.valueOf(vers)));
942 		final long objectCount = NB.decodeUInt32(buf, p + 8);
943 		use(hdrln);
944 		setExpectedObjectCount(objectCount);
945 		onPackHeader(objectCount);
946 	}
947 
948 	private void readPackFooter() throws IOException {
949 		sync();
950 		final byte[] actHash = packDigest.digest();
951 
952 		final int c = fill(Source.INPUT, 20);
953 		final byte[] srcHash = new byte[20];
954 		System.arraycopy(buf, c, srcHash, 0, 20);
955 		use(20);
956 
957 		if (bAvail != 0 && !expectDataAfterPackFooter)
958 			throw new CorruptObjectException(MessageFormat.format(
959 					JGitText.get().expectedEOFReceived,
960 					"\\x" + Integer.toHexString(buf[bOffset] & 0xff))); //$NON-NLS-1$
961 		if (isCheckEofAfterPackFooter()) {
962 			int eof = in.read();
963 			if (0 <= eof)
964 				throw new CorruptObjectException(MessageFormat.format(
965 						JGitText.get().expectedEOFReceived,
966 						"\\x" + Integer.toHexString(eof))); //$NON-NLS-1$
967 		} else if (bAvail > 0 && expectDataAfterPackFooter) {
968 			in.reset();
969 			IO.skipFully(in, bOffset);
970 		}
971 
972 		if (!Arrays.equals(actHash, srcHash))
973 			throw new CorruptObjectException(
974 					JGitText.get().corruptObjectPackfileChecksumIncorrect);
975 
976 		onPackFooter(srcHash);
977 	}
978 
979 	// Cleanup all resources associated with our input parsing.
980 	private void endInput() {
981 		stats.setNumBytesRead(streamPosition());
982 		in = null;
983 	}
984 
985 	// Read one entire object or delta from the input.
986 	private void indexOneObject() throws IOException {
987 		final long streamPosition = streamPosition();
988 
989 		int hdrPtr = 0;
990 		int c = readFrom(Source.INPUT);
991 		hdrBuf[hdrPtr++] = (byte) c;
992 
993 		final int typeCode = (c >> 4) & 7;
994 		long sz = c & 15;
995 		int shift = 4;
996 		while ((c & 0x80) != 0) {
997 			c = readFrom(Source.INPUT);
998 			hdrBuf[hdrPtr++] = (byte) c;
999 			sz += ((long) (c & 0x7f)) << shift;
1000 			shift += 7;
1001 		}
1002 
1003 		checkIfTooLarge(typeCode, sz);
1004 
1005 		switch (typeCode) {
1006 		case Constants.OBJ_COMMIT:
1007 		case Constants.OBJ_TREE:
1008 		case Constants.OBJ_BLOB:
1009 		case Constants.OBJ_TAG:
1010 			stats.addWholeObject(typeCode);
1011 			onBeginWholeObject(streamPosition, typeCode, sz);
1012 			onObjectHeader(Source.INPUT, hdrBuf, 0, hdrPtr);
1013 			whole(streamPosition, typeCode, sz);
1014 			break;
1015 
1016 		case Constants.OBJ_OFS_DELTA: {
1017 			stats.addOffsetDelta();
1018 			c = readFrom(Source.INPUT);
1019 			hdrBuf[hdrPtr++] = (byte) c;
1020 			long ofs = c & 127;
1021 			while ((c & 128) != 0) {
1022 				ofs += 1;
1023 				c = readFrom(Source.INPUT);
1024 				hdrBuf[hdrPtr++] = (byte) c;
1025 				ofs <<= 7;
1026 				ofs += (c & 127);
1027 			}
1028 			final long base = streamPosition - ofs;
1029 			onBeginOfsDelta(streamPosition, base, sz);
1030 			onObjectHeader(Source.INPUT, hdrBuf, 0, hdrPtr);
1031 			inflateAndSkip(Source.INPUT, sz);
1032 			UnresolvedDelta n = onEndDelta();
1033 			n.position = streamPosition;
1034 			n.next = baseByPos.put(base, n);
1035 			deltaCount++;
1036 			break;
1037 		}
1038 
1039 		case Constants.OBJ_REF_DELTA: {
1040 			stats.addRefDelta();
1041 			c = fill(Source.INPUT, 20);
1042 			final ObjectId base = ObjectId.fromRaw(buf, c);
1043 			System.arraycopy(buf, c, hdrBuf, hdrPtr, 20);
1044 			hdrPtr += 20;
1045 			use(20);
1046 			DeltaChain r = baseById.get(base);
1047 			if (r == null) {
1048 				r = new DeltaChain(base);
1049 				baseById.add(r);
1050 			}
1051 			onBeginRefDelta(streamPosition, base, sz);
1052 			onObjectHeader(Source.INPUT, hdrBuf, 0, hdrPtr);
1053 			inflateAndSkip(Source.INPUT, sz);
1054 			UnresolvedDelta n = onEndDelta();
1055 			n.position = streamPosition;
1056 			r.add(n);
1057 			deltaCount++;
1058 			break;
1059 		}
1060 
1061 		default:
1062 			throw new IOException(
1063 					MessageFormat.format(JGitText.get().unknownObjectType,
1064 							Integer.valueOf(typeCode)));
1065 		}
1066 	}
1067 
1068 	private void whole(final long pos, final int type, final long sz)
1069 			throws IOException {
1070 		SHA1 objectDigest = objectHasher.reset();
1071 		objectDigest.update(Constants.encodedTypeString(type));
1072 		objectDigest.update((byte) ' ');
1073 		objectDigest.update(Constants.encodeASCII(sz));
1074 		objectDigest.update((byte) 0);
1075 
1076 		final byte[] data;
1077 		if (type == Constants.OBJ_BLOB) {
1078 			byte[] readBuffer = buffer();
1079 			InputStream inf = inflate(Source.INPUT, sz);
1080 			BlobObjectChecker checker = null;
1081 			if (objCheck != null) {
1082 				checker = objCheck.newBlobObjectChecker();
1083 			}
1084 			if (checker == null) {
1085 				checker = BlobObjectChecker.NULL_CHECKER;
1086 			}
1087 			long cnt = 0;
1088 			while (cnt < sz) {
1089 				int r = inf.read(readBuffer);
1090 				if (r <= 0)
1091 					break;
1092 				objectDigest.update(readBuffer, 0, r);
1093 				checker.update(readBuffer, 0, r);
1094 				cnt += r;
1095 			}
1096 			inf.close();
1097 			objectDigest.digest(tempObjectId);
1098 			checker.endBlob(tempObjectId);
1099 			data = null;
1100 		} else {
1101 			data = inflateAndReturn(Source.INPUT, sz);
1102 			objectDigest.update(data);
1103 			objectDigest.digest(tempObjectId);
1104 			verifySafeObject(tempObjectId, type, data);
1105 		}
1106 
1107 		PackedObjectInfo obj = newInfo(tempObjectId, null, null);
1108 		obj.setOffset(pos);
1109 		obj.setType(type);
1110 		onEndWholeObject(obj);
1111 		if (data != null)
1112 			onInflatedObjectData(obj, type, data);
1113 		addObjectAndTrack(obj);
1114 
1115 		if (isCheckObjectCollisions()) {
1116 			collisionCheckObjs.add(obj);
1117 		}
1118 	}
1119 
1120 	/**
1121 	 * Verify the integrity of the object.
1122 	 *
1123 	 * @param id
1124 	 *            identity of the object to be checked.
1125 	 * @param type
1126 	 *            the type of the object.
1127 	 * @param data
1128 	 *            raw content of the object.
1129 	 * @throws org.eclipse.jgit.errors.CorruptObjectException
1130 	 * @since 4.9
1131 	 */
1132 	protected void verifySafeObject(final AnyObjectId id, final int type,
1133 			final byte[] data) throws CorruptObjectException {
1134 		if (objCheck != null) {
1135 			try {
1136 				objCheck.check(id, type, data);
1137 			} catch (CorruptObjectException e) {
1138 				if (e.getErrorType() != null) {
1139 					throw e;
1140 				}
1141 				throw new CorruptObjectException(
1142 						MessageFormat.format(JGitText.get().invalidObject,
1143 								Constants.typeString(type), id.name(),
1144 								e.getMessage()),
1145 						e);
1146 			}
1147 		}
1148 	}
1149 
1150 	private void checkObjectCollision() throws IOException {
1151 		for (PackedObjectInfo obj : collisionCheckObjs) {
1152 			if (!readCurs.has(obj)) {
1153 				continue;
1154 			}
1155 			checkObjectCollision(obj);
1156 		}
1157 	}
1158 
1159 	private void checkObjectCollision(PackedObjectInfo obj)
1160 			throws IOException {
1161 		ObjectTypeAndSize info = openDatabase(obj, new ObjectTypeAndSize());
1162 		final byte[] readBuffer = buffer();
1163 		final byte[] curBuffer = new byte[readBuffer.length];
1164 		long sz = info.size;
1165 		InputStream pck = null;
1166 		try (ObjectStream cur = readCurs.open(obj, info.type).openStream()) {
1167 			if (cur.getSize() != sz) {
1168 				throw new IOException(MessageFormat.format(
1169 						JGitText.get().collisionOn, obj.name()));
1170 			}
1171 			pck = inflate(Source.DATABASE, sz);
1172 			while (0 < sz) {
1173 				int n = (int) Math.min(readBuffer.length, sz);
1174 				IO.readFully(cur, curBuffer, 0, n);
1175 				IO.readFully(pck, readBuffer, 0, n);
1176 				for (int i = 0; i < n; i++) {
1177 					if (curBuffer[i] != readBuffer[i]) {
1178 						throw new IOException(MessageFormat.format(JGitText
1179 								.get().collisionOn, obj.name()));
1180 					}
1181 				}
1182 				sz -= n;
1183 			}
1184 		} catch (MissingObjectException notLocal) {
1185 			// This is OK, we don't have a copy of the object locally
1186 			// but the API throws when we try to read it as usually its
1187 			// an error to read something that doesn't exist.
1188 		} finally {
1189 			if (pck != null) {
1190 				pck.close();
1191 			}
1192 		}
1193 	}
1194 
1195 	private void checkObjectCollision(AnyObjectId obj, int type, byte[] data)
1196 			throws IOException {
1197 		try {
1198 			final ObjectLoader ldr = readCurs.open(obj, type);
1199 			final byte[] existingData = ldr.getCachedBytes(data.length);
1200 			if (!Arrays.equals(data, existingData)) {
1201 				throw new IOException(MessageFormat.format(
1202 						JGitText.get().collisionOn, obj.name()));
1203 			}
1204 		} catch (MissingObjectException notLocal) {
1205 			// This is OK, we don't have a copy of the object locally
1206 			// but the API throws when we try to read it as usually its
1207 			// an error to read something that doesn't exist.
1208 		}
1209 	}
1210 
1211 	/** @return current position of the input stream being parsed. */
1212 	private long streamPosition() {
1213 		return bBase + bOffset;
1214 	}
1215 
1216 	private ObjectTypeAndSize openDatabase(PackedObjectInfo obj,
1217 			ObjectTypeAndSize info) throws IOException {
1218 		bOffset = 0;
1219 		bAvail = 0;
1220 		return seekDatabase(obj, info);
1221 	}
1222 
1223 	private ObjectTypeAndSize openDatabase(UnresolvedDelta delta,
1224 			ObjectTypeAndSize info) throws IOException {
1225 		bOffset = 0;
1226 		bAvail = 0;
1227 		return seekDatabase(delta, info);
1228 	}
1229 
1230 	// Consume exactly one byte from the buffer and return it.
1231 	private int readFrom(final Source src) throws IOException {
1232 		if (bAvail == 0)
1233 			fill(src, 1);
1234 		bAvail--;
1235 		return buf[bOffset++] & 0xff;
1236 	}
1237 
1238 	// Consume cnt bytes from the buffer.
1239 	void use(final int cnt) {
1240 		bOffset += cnt;
1241 		bAvail -= cnt;
1242 	}
1243 
1244 	// Ensure at least need bytes are available in in {@link #buf}.
1245 	int fill(final Source src, final int need) throws IOException {
1246 		while (bAvail < need) {
1247 			int next = bOffset + bAvail;
1248 			int free = buf.length - next;
1249 			if (free + bAvail < need) {
1250 				switch (src) {
1251 				case INPUT:
1252 					sync();
1253 					break;
1254 				case DATABASE:
1255 					if (bAvail > 0)
1256 						System.arraycopy(buf, bOffset, buf, 0, bAvail);
1257 					bOffset = 0;
1258 					break;
1259 				}
1260 				next = bAvail;
1261 				free = buf.length - next;
1262 			}
1263 			switch (src) {
1264 			case INPUT:
1265 				next = in.read(buf, next, free);
1266 				break;
1267 			case DATABASE:
1268 				next = readDatabase(buf, next, free);
1269 				break;
1270 			}
1271 			if (next <= 0)
1272 				throw new EOFException(
1273 						JGitText.get().packfileIsTruncatedNoParam);
1274 			bAvail += next;
1275 		}
1276 		return bOffset;
1277 	}
1278 
1279 	// Store consumed bytes in {@link #buf} up to {@link #bOffset}.
1280 	private void sync() throws IOException {
1281 		packDigest.update(buf, 0, bOffset);
1282 		onStoreStream(buf, 0, bOffset);
1283 		if (expectDataAfterPackFooter) {
1284 			if (bAvail > 0) {
1285 				in.reset();
1286 				IO.skipFully(in, bOffset);
1287 				bAvail = 0;
1288 			}
1289 			in.mark(buf.length);
1290 		} else if (bAvail > 0)
1291 			System.arraycopy(buf, bOffset, buf, 0, bAvail);
1292 		bBase += bOffset;
1293 		bOffset = 0;
1294 	}
1295 
1296 	/**
1297 	 * Get a temporary byte array for use by the caller.
1298 	 *
1299 	 * @return a temporary byte array for use by the caller.
1300 	 */
1301 	protected byte[] buffer() {
1302 		return tempBuffer;
1303 	}
1304 
1305 	/**
1306 	 * Construct a PackedObjectInfo instance for this parser.
1307 	 *
1308 	 * @param id
1309 	 *            identity of the object to be tracked.
1310 	 * @param delta
1311 	 *            if the object was previously an unresolved delta, this is the
1312 	 *            delta object that was tracking it. Otherwise null.
1313 	 * @param deltaBase
1314 	 *            if the object was previously an unresolved delta, this is the
1315 	 *            ObjectId of the base of the delta. The base may be outside of
1316 	 *            the pack stream if the stream was a thin-pack.
1317 	 * @return info object containing this object's data.
1318 	 */
1319 	protected PackedObjectInfo newInfo(AnyObjectId id, UnresolvedDelta delta,
1320 			ObjectId deltaBase) {
1321 		PackedObjectInfo oe = new PackedObjectInfo(id);
1322 		if (delta != null)
1323 			oe.setCRC(delta.crc);
1324 		return oe;
1325 	}
1326 
1327 	/**
1328 	 * Set the expected number of objects in the pack stream.
1329 	 * <p>
1330 	 * The object count in the pack header is not always correct for some Dfs
1331 	 * pack files. e.g. INSERT pack always assume 1 object in the header since
1332 	 * the actual object count is unknown when the pack is written.
1333 	 * <p>
1334 	 * If external implementation wants to overwrite the expectedObjectCount,
1335 	 * they should call this method during {@link #onPackHeader(long)}.
1336 	 *
1337 	 * @param expectedObjectCount a long.
1338 	 * @since 4.9
1339 	 */
1340 	protected void setExpectedObjectCount(long expectedObjectCount) {
1341 		this.expectedObjectCount = expectedObjectCount;
1342 	}
1343 
1344 	/**
1345 	 * Store bytes received from the raw stream.
1346 	 * <p>
1347 	 * This method is invoked during {@link #parse(ProgressMonitor)} as data is
1348 	 * consumed from the incoming stream. Implementors may use this event to
1349 	 * archive the raw incoming stream to the destination repository in large
1350 	 * chunks, without paying attention to object boundaries.
1351 	 * <p>
1352 	 * The only component of the pack not supplied to this method is the last 20
1353 	 * bytes of the pack that comprise the trailing SHA-1 checksum. Those are
1354 	 * passed to {@link #onPackFooter(byte[])}.
1355 	 *
1356 	 * @param raw
1357 	 *            buffer to copy data out of.
1358 	 * @param pos
1359 	 *            first offset within the buffer that is valid.
1360 	 * @param len
1361 	 *            number of bytes in the buffer that are valid.
1362 	 * @throws java.io.IOException
1363 	 *             the stream cannot be archived.
1364 	 */
1365 	protected abstract void onStoreStream(byte[] raw, int pos, int len)
1366 			throws IOException;
1367 
1368 	/**
1369 	 * Store (and/or checksum) an object header.
1370 	 * <p>
1371 	 * Invoked after any of the {@code onBegin()} events. The entire header is
1372 	 * supplied in a single invocation, before any object data is supplied.
1373 	 *
1374 	 * @param src
1375 	 *            where the data came from
1376 	 * @param raw
1377 	 *            buffer to read data from.
1378 	 * @param pos
1379 	 *            first offset within buffer that is valid.
1380 	 * @param len
1381 	 *            number of bytes in buffer that are valid.
1382 	 * @throws java.io.IOException
1383 	 *             the stream cannot be archived.
1384 	 */
1385 	protected abstract void onObjectHeader(Source src, byte[] raw, int pos,
1386 			int len) throws IOException;
1387 
1388 	/**
1389 	 * Store (and/or checksum) a portion of an object's data.
1390 	 * <p>
1391 	 * This method may be invoked multiple times per object, depending on the
1392 	 * size of the object, the size of the parser's internal read buffer, and
1393 	 * the alignment of the object relative to the read buffer.
1394 	 * <p>
1395 	 * Invoked after {@link #onObjectHeader(Source, byte[], int, int)}.
1396 	 *
1397 	 * @param src
1398 	 *            where the data came from
1399 	 * @param raw
1400 	 *            buffer to read data from.
1401 	 * @param pos
1402 	 *            first offset within buffer that is valid.
1403 	 * @param len
1404 	 *            number of bytes in buffer that are valid.
1405 	 * @throws java.io.IOException
1406 	 *             the stream cannot be archived.
1407 	 */
1408 	protected abstract void onObjectData(Source src, byte[] raw, int pos,
1409 			int len) throws IOException;
1410 
1411 	/**
1412 	 * Invoked for commits, trees, tags, and small blobs.
1413 	 *
1414 	 * @param obj
1415 	 *            the object info, populated.
1416 	 * @param typeCode
1417 	 *            the type of the object.
1418 	 * @param data
1419 	 *            inflated data for the object.
1420 	 * @throws java.io.IOException
1421 	 *             the object cannot be archived.
1422 	 */
1423 	protected abstract void onInflatedObjectData(PackedObjectInfo obj,
1424 			int typeCode, byte[] data) throws IOException;
1425 
1426 	/**
1427 	 * Provide the implementation with the original stream's pack header.
1428 	 *
1429 	 * @param objCnt
1430 	 *            number of objects expected in the stream.
1431 	 * @throws java.io.IOException
1432 	 *             the implementation refuses to work with this many objects.
1433 	 */
1434 	protected abstract void onPackHeader(long objCnt) throws IOException;
1435 
1436 	/**
1437 	 * Provide the implementation with the original stream's pack footer.
1438 	 *
1439 	 * @param hash
1440 	 *            the trailing 20 bytes of the pack, this is a SHA-1 checksum of
1441 	 *            all of the pack data.
1442 	 * @throws java.io.IOException
1443 	 *             the stream cannot be archived.
1444 	 */
1445 	protected abstract void onPackFooter(byte[] hash) throws IOException;
1446 
1447 	/**
1448 	 * Provide the implementation with a base that was outside of the pack.
1449 	 * <p>
1450 	 * This event only occurs on a thin pack for base objects that were outside
1451 	 * of the pack and came from the local repository. Usually an implementation
1452 	 * uses this event to compress the base and append it onto the end of the
1453 	 * pack, so the pack stays self-contained.
1454 	 *
1455 	 * @param typeCode
1456 	 *            type of the base object.
1457 	 * @param data
1458 	 *            complete content of the base object.
1459 	 * @param info
1460 	 *            packed object information for this base. Implementors must
1461 	 *            populate the CRC and offset members if returning true.
1462 	 * @return true if the {@code info} should be included in the object list
1463 	 *         returned by {@link #getSortedObjectList(Comparator)}, false if it
1464 	 *         should not be included.
1465 	 * @throws java.io.IOException
1466 	 *             the base could not be included into the pack.
1467 	 */
1468 	protected abstract boolean onAppendBase(int typeCode, byte[] data,
1469 			PackedObjectInfo info) throws IOException;
1470 
1471 	/**
1472 	 * Event indicating a thin pack has been completely processed.
1473 	 * <p>
1474 	 * This event is invoked only if a thin pack has delta references to objects
1475 	 * external from the pack. The event is called after all of those deltas
1476 	 * have been resolved.
1477 	 *
1478 	 * @throws java.io.IOException
1479 	 *             the pack cannot be archived.
1480 	 */
1481 	protected abstract void onEndThinPack() throws IOException;
1482 
1483 	/**
1484 	 * Reposition the database to re-read a previously stored object.
1485 	 * <p>
1486 	 * If the database is computing CRC-32 checksums for object data, it should
1487 	 * reset its internal CRC instance during this method call.
1488 	 *
1489 	 * @param obj
1490 	 *            the object position to begin reading from. This is from
1491 	 *            {@link #newInfo(AnyObjectId, UnresolvedDelta, ObjectId)}.
1492 	 * @param info
1493 	 *            object to populate with type and size.
1494 	 * @return the {@code info} object.
1495 	 * @throws java.io.IOException
1496 	 *             the database cannot reposition to this location.
1497 	 */
1498 	protected abstract ObjectTypeAndSize seekDatabase(PackedObjectInfo obj,
1499 			ObjectTypeAndSize info) throws IOException;
1500 
1501 	/**
1502 	 * Reposition the database to re-read a previously stored object.
1503 	 * <p>
1504 	 * If the database is computing CRC-32 checksums for object data, it should
1505 	 * reset its internal CRC instance during this method call.
1506 	 *
1507 	 * @param delta
1508 	 *            the object position to begin reading from. This is an instance
1509 	 *            previously returned by {@link #onEndDelta()}.
1510 	 * @param info
1511 	 *            object to populate with type and size.
1512 	 * @return the {@code info} object.
1513 	 * @throws java.io.IOException
1514 	 *             the database cannot reposition to this location.
1515 	 */
1516 	protected abstract ObjectTypeAndSize seekDatabase(UnresolvedDelta delta,
1517 			ObjectTypeAndSize info) throws IOException;
1518 
1519 	/**
1520 	 * Read from the database's current position into the buffer.
1521 	 *
1522 	 * @param dst
1523 	 *            the buffer to copy read data into.
1524 	 * @param pos
1525 	 *            position within {@code dst} to start copying data into.
1526 	 * @param cnt
1527 	 *            ideal target number of bytes to read. Actual read length may
1528 	 *            be shorter.
1529 	 * @return number of bytes stored.
1530 	 * @throws java.io.IOException
1531 	 *             the database cannot be accessed.
1532 	 */
1533 	protected abstract int readDatabase(byte[] dst, int pos, int cnt)
1534 			throws IOException;
1535 
1536 	/**
1537 	 * Check the current CRC matches the expected value.
1538 	 * <p>
1539 	 * This method is invoked when an object is read back in from the database
1540 	 * and its data is used during delta resolution. The CRC is validated after
1541 	 * the object has been fully read, allowing the parser to verify there was
1542 	 * no silent data corruption.
1543 	 * <p>
1544 	 * Implementations are free to ignore this check by always returning true if
1545 	 * they are performing other data integrity validations at a lower level.
1546 	 *
1547 	 * @param oldCRC
1548 	 *            the prior CRC that was recorded during the first scan of the
1549 	 *            object from the pack stream.
1550 	 * @return true if the CRC matches; false if it does not.
1551 	 */
1552 	protected abstract boolean checkCRC(int oldCRC);
1553 
1554 	/**
1555 	 * Event notifying the start of an object stored whole (not as a delta).
1556 	 *
1557 	 * @param streamPosition
1558 	 *            position of this object in the incoming stream.
1559 	 * @param type
1560 	 *            type of the object; one of
1561 	 *            {@link org.eclipse.jgit.lib.Constants#OBJ_COMMIT},
1562 	 *            {@link org.eclipse.jgit.lib.Constants#OBJ_TREE},
1563 	 *            {@link org.eclipse.jgit.lib.Constants#OBJ_BLOB}, or
1564 	 *            {@link org.eclipse.jgit.lib.Constants#OBJ_TAG}.
1565 	 * @param inflatedSize
1566 	 *            size of the object when fully inflated. The size stored within
1567 	 *            the pack may be larger or smaller, and is not yet known.
1568 	 * @throws java.io.IOException
1569 	 *             the object cannot be recorded.
1570 	 */
1571 	protected abstract void onBeginWholeObject(long streamPosition, int type,
1572 			long inflatedSize) throws IOException;
1573 
1574 	/**
1575 	 * Event notifying the the current object.
1576 	 *
1577 	 *@param info
1578 	 *            object information.
1579 	 * @throws java.io.IOException
1580 	 *             the object cannot be recorded.
1581 	 */
1582 	protected abstract void onEndWholeObject(PackedObjectInfo info)
1583 			throws IOException;
1584 
1585 	/**
1586 	 * Event notifying start of a delta referencing its base by offset.
1587 	 *
1588 	 * @param deltaStreamPosition
1589 	 *            position of this object in the incoming stream.
1590 	 * @param baseStreamPosition
1591 	 *            position of the base object in the incoming stream. The base
1592 	 *            must be before the delta, therefore {@code baseStreamPosition
1593 	 *            &lt; deltaStreamPosition}. This is <b>not</b> the position
1594 	 *            returned by a prior end object event.
1595 	 * @param inflatedSize
1596 	 *            size of the delta when fully inflated. The size stored within
1597 	 *            the pack may be larger or smaller, and is not yet known.
1598 	 * @throws java.io.IOException
1599 	 *             the object cannot be recorded.
1600 	 */
1601 	protected abstract void onBeginOfsDelta(long deltaStreamPosition,
1602 			long baseStreamPosition, long inflatedSize) throws IOException;
1603 
1604 	/**
1605 	 * Event notifying start of a delta referencing its base by ObjectId.
1606 	 *
1607 	 * @param deltaStreamPosition
1608 	 *            position of this object in the incoming stream.
1609 	 * @param baseId
1610 	 *            name of the base object. This object may be later in the
1611 	 *            stream, or might not appear at all in the stream (in the case
1612 	 *            of a thin-pack).
1613 	 * @param inflatedSize
1614 	 *            size of the delta when fully inflated. The size stored within
1615 	 *            the pack may be larger or smaller, and is not yet known.
1616 	 * @throws java.io.IOException
1617 	 *             the object cannot be recorded.
1618 	 */
1619 	protected abstract void onBeginRefDelta(long deltaStreamPosition,
1620 			AnyObjectId baseId, long inflatedSize) throws IOException;
1621 
1622 	/**
1623 	 * Event notifying the the current object.
1624 	 *
1625 	 *@return object information that must be populated with at least the
1626 	 *         offset.
1627 	 * @throws java.io.IOException
1628 	 *             the object cannot be recorded.
1629 	 */
1630 	protected UnresolvedDelta onEndDelta() throws IOException {
1631 		return new UnresolvedDelta();
1632 	}
1633 
1634 	/** Type and size information about an object in the database buffer. */
1635 	public static class ObjectTypeAndSize {
1636 		/** The type of the object. */
1637 		public int type;
1638 
1639 		/** The inflated size of the object. */
1640 		public long size;
1641 	}
1642 
1643 	private void inflateAndSkip(final Source src, final long inflatedSize)
1644 			throws IOException {
1645 		final InputStream inf = inflate(src, inflatedSize);
1646 		IO.skipFully(inf, inflatedSize);
1647 		inf.close();
1648 	}
1649 
1650 	private byte[] inflateAndReturn(final Source src, final long inflatedSize)
1651 			throws IOException {
1652 		final byte[] dst = new byte[(int) inflatedSize];
1653 		final InputStream inf = inflate(src, inflatedSize);
1654 		IO.readFully(inf, dst, 0, dst.length);
1655 		inf.close();
1656 		return dst;
1657 	}
1658 
1659 	private InputStream inflate(final Source src, final long inflatedSize)
1660 			throws IOException {
1661 		inflater.open(src, inflatedSize);
1662 		return inflater;
1663 	}
1664 
1665 	private static class DeltaChain extends ObjectIdOwnerMap.Entry {
1666 		UnresolvedDelta head;
1667 
1668 		DeltaChain(final AnyObjectId id) {
1669 			super(id);
1670 		}
1671 
1672 		UnresolvedDelta remove() {
1673 			final UnresolvedDelta r = head;
1674 			if (r != null)
1675 				head = null;
1676 			return r;
1677 		}
1678 
1679 		void add(final UnresolvedDelta d) {
1680 			d.next = head;
1681 			head = d;
1682 		}
1683 	}
1684 
1685 	/** Information about an unresolved delta in this pack stream. */
1686 	public static class UnresolvedDelta {
1687 		long position;
1688 
1689 		int crc;
1690 
1691 		UnresolvedDelta next;
1692 
1693 		/** @return offset within the input stream. */
1694 		public long getOffset() {
1695 			return position;
1696 		}
1697 
1698 		/** @return the CRC-32 checksum of the stored delta data. */
1699 		public int getCRC() {
1700 			return crc;
1701 		}
1702 
1703 		/**
1704 		 * @param crc32
1705 		 *            the CRC-32 checksum of the stored delta data.
1706 		 */
1707 		public void setCRC(int crc32) {
1708 			crc = crc32;
1709 		}
1710 	}
1711 
1712 	private static class DeltaVisit {
1713 		final UnresolvedDelta delta;
1714 
1715 		ObjectId id;
1716 
1717 		byte[] data;
1718 
1719 		DeltaVisit parent;
1720 
1721 		UnresolvedDelta nextChild;
1722 
1723 		DeltaVisit() {
1724 			this.delta = null; // At the root of the stack we have a base.
1725 		}
1726 
1727 		DeltaVisit(DeltaVisit parent) {
1728 			this.parent = parent;
1729 			this.delta = parent.nextChild;
1730 			parent.nextChild = delta.next;
1731 		}
1732 
1733 		DeltaVisit next() {
1734 			// If our parent has no more children, discard it.
1735 			if (parent != null && parent.nextChild == null) {
1736 				parent.data = null;
1737 				parent = parent.parent;
1738 			}
1739 
1740 			if (nextChild != null)
1741 				return new DeltaVisit(this);
1742 
1743 			// If we have no child ourselves, our parent must (if it exists),
1744 			// due to the discard rule above. With no parent, we are done.
1745 			if (parent != null)
1746 				return new DeltaVisit(parent);
1747 			return null;
1748 		}
1749 	}
1750 
1751 	private void addObjectAndTrack(PackedObjectInfo oe) {
1752 		entries[entryCount++] = oe;
1753 		if (needNewObjectIds())
1754 			newObjectIds.add(oe);
1755 	}
1756 
1757 	private class InflaterStream extends InputStream {
1758 		private final Inflater inf;
1759 
1760 		private final byte[] skipBuffer;
1761 
1762 		private Source src;
1763 
1764 		private long expectedSize;
1765 
1766 		private long actualSize;
1767 
1768 		private int p;
1769 
1770 		InflaterStream() {
1771 			inf = InflaterCache.get();
1772 			skipBuffer = new byte[512];
1773 		}
1774 
1775 		void release() {
1776 			inf.reset();
1777 			InflaterCache.release(inf);
1778 		}
1779 
1780 		void open(Source source, long inflatedSize) throws IOException {
1781 			src = source;
1782 			expectedSize = inflatedSize;
1783 			actualSize = 0;
1784 
1785 			p = fill(src, 1);
1786 			inf.setInput(buf, p, bAvail);
1787 		}
1788 
1789 		@Override
1790 		public long skip(long toSkip) throws IOException {
1791 			long n = 0;
1792 			while (n < toSkip) {
1793 				final int cnt = (int) Math.min(skipBuffer.length, toSkip - n);
1794 				final int r = read(skipBuffer, 0, cnt);
1795 				if (r <= 0)
1796 					break;
1797 				n += r;
1798 			}
1799 			return n;
1800 		}
1801 
1802 		@Override
1803 		public int read() throws IOException {
1804 			int n = read(skipBuffer, 0, 1);
1805 			return n == 1 ? skipBuffer[0] & 0xff : -1;
1806 		}
1807 
1808 		@Override
1809 		public int read(byte[] dst, int pos, int cnt) throws IOException {
1810 			try {
1811 				int n = 0;
1812 				while (n < cnt) {
1813 					int r = inf.inflate(dst, pos + n, cnt - n);
1814 					n += r;
1815 					if (inf.finished())
1816 						break;
1817 					if (inf.needsInput()) {
1818 						onObjectData(src, buf, p, bAvail);
1819 						use(bAvail);
1820 
1821 						p = fill(src, 1);
1822 						inf.setInput(buf, p, bAvail);
1823 					} else if (r == 0) {
1824 						throw new CorruptObjectException(MessageFormat.format(
1825 								JGitText.get().packfileCorruptionDetected,
1826 								JGitText.get().unknownZlibError));
1827 					}
1828 				}
1829 				actualSize += n;
1830 				return 0 < n ? n : -1;
1831 			} catch (DataFormatException dfe) {
1832 				throw new CorruptObjectException(MessageFormat.format(JGitText
1833 						.get().packfileCorruptionDetected, dfe.getMessage()));
1834 			}
1835 		}
1836 
1837 		@Override
1838 		public void close() throws IOException {
1839 			// We need to read here to enter the loop above and pump the
1840 			// trailing checksum into the Inflater. It should return -1 as the
1841 			// caller was supposed to consume all content.
1842 			//
1843 			if (read(skipBuffer) != -1 || actualSize != expectedSize) {
1844 				throw new CorruptObjectException(MessageFormat.format(JGitText
1845 						.get().packfileCorruptionDetected,
1846 						JGitText.get().wrongDecompressedLength));
1847 			}
1848 
1849 			int used = bAvail - inf.getRemaining();
1850 			if (0 < used) {
1851 				onObjectData(src, buf, p, used);
1852 				use(used);
1853 			}
1854 
1855 			inf.reset();
1856 		}
1857 	}
1858 }