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