@ -131,6 +131,19 @@ public class IndexPack {
return ip ;
}
private static enum Source {
/** Data is read from the incoming stream. */
INPUT ,
/ * *
* Data is read from the spooled pack file .
* < p >
* During streaming , some ( or all ) data might be saved into the spooled
* pack file so it can be randomly accessed later .
* /
FILE ;
}
private final Repository repo ;
/ * *
@ -200,7 +213,7 @@ public class IndexPack {
private LongMap < UnresolvedDelta > baseByPos ;
private byte [ ] objectData ;
private byte [ ] skipBuffer ;
private MessageDigest packDigest ;
@ -232,7 +245,7 @@ public class IndexPack {
inflater = InflaterCache . get ( ) ;
readCurs = new WindowCursor ( ) ;
buf = new byte [ BUFFER_SIZE ] ;
objectData = new byte [ BUFFER_SIZE ] ;
skipBuffer = new byte [ 512 ] ;
objectDigest = Constants . newMessageDigest ( ) ;
tempObjectId = new MutableObjectId ( ) ;
packDigest = Constants . newMessageDigest ( ) ;
@ -474,12 +487,12 @@ public class IndexPack {
byte [ ] data , PackedObjectInfo oe ) throws IOException {
crc . reset ( ) ;
position ( pos ) ;
int c = readFromFile ( ) ;
int c = readFrom ( Source . FILE ) ;
final int typeCode = ( c > > 4 ) & 7 ;
long sz = c & 15 ;
int shift = 4 ;
while ( ( c & 0x80 ) ! = 0 ) {
c = readFromFile ( ) ;
c = readFrom ( Source . FILE ) ;
sz + = ( c & 0x7f ) < < shift ;
shift + = 7 ;
}
@ -490,19 +503,19 @@ public class IndexPack {
case Constants . OBJ_BLOB :
case Constants . OBJ_TAG :
type = typeCode ;
data = inflateFromFile ( ( int ) sz ) ;
data = inflateAndReturn ( Source . FILE , sz ) ;
break ;
case Constants . OBJ_OFS_DELTA : {
c = readFromFile ( ) & 0xff ;
c = readFrom ( Source . FILE ) & 0xff ;
while ( ( c & 128 ) ! = 0 )
c = readFromFile ( ) & 0xff ;
data = BinaryDelta . apply ( data , inflateFromFile ( ( int ) sz ) ) ;
c = readFrom ( Source . FILE ) & 0xff ;
data = BinaryDelta . apply ( data , inflateAndReturn ( Source . FILE , sz ) ) ;
break ;
}
case Constants . OBJ_REF_DELTA : {
crc . update ( buf , fillFromFile ( 20 ) , 20 ) ;
crc . update ( buf , fill ( Source . FILE , 20 ) , 20 ) ;
use ( 20 ) ;
data = BinaryDelta . apply ( data , inflateFromFile ( ( int ) sz ) ) ;
data = BinaryDelta . apply ( data , inflateAndReturn ( Source . FILE , sz ) ) ;
break ;
}
default :
@ -657,7 +670,7 @@ public class IndexPack {
packOut . seek ( 0 ) ;
bAvail = 0 ;
bOffset = 0 ;
fillFromFile ( 12 ) ;
fill ( Source . FILE , 12 ) ;
{
final int origCnt = ( int ) Math . min ( bAvail , origRemaining ) ;
@ -728,7 +741,7 @@ public class IndexPack {
private void readPackHeader ( ) throws IOException {
final int hdrln = Constants . PACK_SIGNATURE . length + 4 + 4 ;
final int p = fillFromInput ( hdrln ) ;
final int p = fill ( Source . INPUT , hdrln ) ;
for ( int k = 0 ; k < Constants . PACK_SIGNATURE . length ; k + + )
if ( buf [ p + k ] ! = Constants . PACK_SIGNATURE [ k ] )
throw new IOException ( JGitText . get ( ) . notAPACKFile ) ;
@ -743,7 +756,7 @@ public class IndexPack {
private void readPackFooter ( ) throws IOException {
sync ( ) ;
final byte [ ] cmpcsum = packDigest . digest ( ) ;
final int c = fillFromInput ( 20 ) ;
final int c = fill ( Source . INPUT , 20 ) ;
packcsum = new byte [ 20 ] ;
System . arraycopy ( buf , c , packcsum , 0 , 20 ) ;
use ( 20 ) ;
@ -757,7 +770,7 @@ public class IndexPack {
// Cleanup all resources associated with our input parsing.
private void endInput ( ) {
in = null ;
objectData = null ;
skipBuffer = null ;
}
// Read one entire object or delta from the input.
@ -765,12 +778,12 @@ public class IndexPack {
final long pos = position ( ) ;
crc . reset ( ) ;
int c = readFromInput ( ) ;
int c = readFrom ( Source . INPUT ) ;
final int typeCode = ( c > > 4 ) & 7 ;
long sz = c & 15 ;
int shift = 4 ;
while ( ( c & 0x80 ) ! = 0 ) {
c = readFromInput ( ) ;
c = readFrom ( Source . INPUT ) ;
sz + = ( c & 0x7f ) < < shift ;
shift + = 7 ;
}
@ -783,24 +796,24 @@ public class IndexPack {
whole ( typeCode , pos , sz ) ;
break ;
case Constants . OBJ_OFS_DELTA : {
c = readFromInput ( ) ;
c = readFrom ( Source . INPUT ) ;
long ofs = c & 127 ;
while ( ( c & 128 ) ! = 0 ) {
ofs + = 1 ;
c = readFromInput ( ) ;
c = readFrom ( Source . INPUT ) ;
ofs < < = 7 ;
ofs + = ( c & 127 ) ;
}
final long base = pos - ofs ;
final UnresolvedDelta n ;
skipInflateFromInput ( sz ) ;
inflateAndSkip ( Source . INPUT , sz ) ;
n = new UnresolvedDelta ( pos , ( int ) crc . getValue ( ) ) ;
n . next = baseByPos . put ( base , n ) ;
deltaCount + + ;
break ;
}
case Constants . OBJ_REF_DELTA : {
c = fillFromInput ( 20 ) ;
c = fill ( Source . INPUT , 20 ) ;
crc . update ( buf , c , 20 ) ;
final ObjectId base = ObjectId . fromRaw ( buf , c ) ;
use ( 20 ) ;
@ -809,7 +822,7 @@ public class IndexPack {
r = new DeltaChain ( base ) ;
baseById . add ( r ) ;
}
skipInflateFromInput ( sz ) ;
inflateAndSkip ( Source . INPUT , sz ) ;
r . add ( new UnresolvedDelta ( pos , ( int ) crc . getValue ( ) ) ) ;
deltaCount + + ;
break ;
@ -821,7 +834,7 @@ public class IndexPack {
private void whole ( final int type , final long pos , final long sz )
throws IOException {
final byte [ ] data = inflateFromInput ( sz ) ;
final byte [ ] data = inflateAndReturn ( Source . INPUT , sz ) ;
objectDigest . update ( Constants . encodedTypeString ( type ) ) ;
objectDigest . update ( ( byte ) ' ' ) ;
objectDigest . update ( Constants . encodeASCII ( sz ) ) ;
@ -867,19 +880,9 @@ public class IndexPack {
}
// Consume exactly one byte from the buffer and return it.
private int readFromInput ( ) throws IOException {
if ( bAvail = = 0 )
fillFromInput ( 1 ) ;
bAvail - - ;
final int b = buf [ bOffset + + ] & 0xff ;
crc . update ( b ) ;
return b ;
}
// Consume exactly one byte from the buffer and return it.
private int readFromFile ( ) throws IOException {
private int readFrom ( final Source src ) throws IOException {
if ( bAvail = = 0 )
fillFromFile ( 1 ) ;
fill ( src , 1 ) ;
bAvail - - ;
final int b = buf [ bOffset + + ] & 0xff ;
crc . update ( b ) ;
@ -893,36 +896,32 @@ public class IndexPack {
}
// Ensure at least need bytes are available in in {@link #buf}.
private int fillFromInput ( final int need ) throws IOException {
private int fill ( final Source src , final int need ) throws IOException {
while ( bAvail < need ) {
int next = bOffset + bAvail ;
int free = buf . length - next ;
if ( free + bAvail < need ) {
sync ( ) ;
switch ( src ) {
case INPUT :
sync ( ) ;
break ;
case FILE :
if ( bAvail > 0 )
System . arraycopy ( buf , bOffset , buf , 0 , bAvail ) ;
bOffset = 0 ;
break ;
}
next = bAvail ;
free = buf . length - next ;
}
next = in . read ( buf , next , free ) ;
if ( next < = 0 )
throw new EOFException ( JGitText . get ( ) . packfileIsTruncated ) ;
bAvail + = next ;
}
return bOffset ;
}
// Ensure at least need bytes are available in in {@link #buf}.
private int fillFromFile ( final int need ) throws IOException {
if ( bAvail < need ) {
int next = bOffset + bAvail ;
int free = buf . length - next ;
if ( free + bAvail < need ) {
if ( bAvail > 0 )
System . arraycopy ( buf , bOffset , buf , 0 , bAvail ) ;
bOffset = 0 ;
next = bAvail ;
free = buf . length - next ;
switch ( src ) {
case INPUT :
next = in . read ( buf , next , free ) ;
break ;
case FILE :
next = packOut . read ( buf , next , free ) ;
break ;
}
next = packOut . read ( buf , next , free ) ;
if ( next < = 0 )
throw new EOFException ( JGitText . get ( ) . packfileIsTruncated ) ;
bAvail + = next ;
@ -941,112 +940,69 @@ public class IndexPack {
bOffset = 0 ;
}
private void skipInflateFromInput ( long sz ) throws IOException {
final Inflater inf = inflater ;
try {
final byte [ ] dst = objectData ;
int n = 0 ;
int p = - 1 ;
while ( ! inf . finished ( ) ) {
if ( inf . needsInput ( ) ) {
if ( p > = 0 ) {
crc . update ( buf , p , bAvail ) ;
use ( bAvail ) ;
}
p = fillFromInput ( 1 ) ;
inf . setInput ( buf , p , bAvail ) ;
}
int free = dst . length - n ;
if ( free < 8 ) {
sz - = n ;
n = 0 ;
free = dst . length ;
}
n + = inf . inflate ( dst , n , free ) ;
}
if ( n ! = sz )
throw new DataFormatException ( JGitText . get ( ) . wrongDecompressedLength ) ;
n = bAvail - inf . getRemaining ( ) ;
if ( n > 0 ) {
crc . update ( buf , p , n ) ;
use ( n ) ;
}
} catch ( DataFormatException dfe ) {
throw corrupt ( dfe ) ;
} finally {
inf . reset ( ) ;
}
private void inflateAndSkip ( final Source src , final long inflatedSize )
throws IOException {
inflate ( src , inflatedSize , skipBuffer , false /* do not keep result */ ) ;
}
private byte [ ] inflateFromInput ( final long sz ) throws IOException {
final byte [ ] dst = new byte [ ( int ) sz ] ;
final Inflater inf = inflater ;
try {
int n = 0 ;
int p = - 1 ;
while ( ! inf . finished ( ) ) {
if ( inf . needsInput ( ) ) {
if ( p > = 0 ) {
crc . update ( buf , p , bAvail ) ;
use ( bAvail ) ;
}
p = fillFromInput ( 1 ) ;
inf . setInput ( buf , p , bAvail ) ;
}
n + = inf . inflate ( dst , n , dst . length - n ) ;
}
if ( n ! = sz )
throw new DataFormatException ( JGitText . get ( ) . wrongDecompressedLength ) ;
n = bAvail - inf . getRemaining ( ) ;
if ( n > 0 ) {
crc . update ( buf , p , n ) ;
use ( n ) ;
}
return dst ;
} catch ( DataFormatException dfe ) {
throw corrupt ( dfe ) ;
} finally {
inf . reset ( ) ;
}
private byte [ ] inflateAndReturn ( final Source src , final long inflatedSize )
throws IOException {
final byte [ ] dst = new byte [ ( int ) inflatedSize ] ;
inflate ( src , inflatedSize , dst , true /* keep result in dst */ ) ;
return dst ;
}
private byte [ ] inflateFromFile ( final int sz ) throws IOException {
private void inflate ( final Source src , final long inflatedSize ,
final byte [ ] dst , final boolean keep ) throws IOException {
final Inflater inf = inflater ;
try {
final byte [ ] dst = new byte [ sz ] ;
int n = 0 ;
int p = - 1 ;
while ( ! inf . finished ( ) ) {
if ( inf . needsInput ( ) ) {
if ( p > = 0 ) {
crc . update ( buf , p , bAvail ) ;
use ( bAvail ) ;
int off = 0 ;
long cnt = 0 ;
int p = fill ( src , 24 ) ;
inf . setInput ( buf , p , bAvail ) ;
do {
int r = inf . inflate ( dst , off , dst . length - off ) ;
if ( r = = 0 ) {
if ( inf . finished ( ) )
break ;
if ( inf . needsInput ( ) ) {
if ( p > = 0 ) {
crc . update ( buf , p , bAvail ) ;
use ( bAvail ) ;
}
p = fill ( src , 24 ) ;
inf . setInput ( buf , p , bAvail ) ;
} else {
throw new CorruptObjectException ( MessageFormat . format (
JGitText . get ( ) . packfileCorruptionDetected ,
JGitText . get ( ) . unknownZlibError ) ) ;
}
p = fillFromFile ( 1 ) ;
inf . setInput ( buf , p , bAvail ) ;
}
n + = inf . inflate ( dst , n , sz - n ) ;
cnt + = r ;
if ( keep )
off + = r ;
} while ( cnt < inflatedSize ) ;
if ( ! inf . finished ( ) | | cnt ! = inflatedSize ) {
throw new CorruptObjectException ( MessageFormat . format ( JGitText
. get ( ) . packfileCorruptionDetected ,
JGitText . get ( ) . wrongDecompressedLength ) ) ;
}
n = bAvail - inf . getRemaining ( ) ;
if ( n > 0 ) {
crc . update ( buf , p , n ) ;
use ( n ) ;
int left = bAvail - inf . getRemaining ( ) ;
if ( left > 0 ) {
crc . update ( buf , p , left ) ;
use ( left ) ;
}
return dst ;
} catch ( DataFormatException dfe ) {
throw corrupt ( dfe ) ;
throw new CorruptObjectException ( MessageFormat . format ( JGitText
. get ( ) . packfileCorruptionDetected , dfe . getMessage ( ) ) ) ;
} finally {
inf . reset ( ) ;
}
}
private static CorruptObjectException corrupt ( final DataFormatException dfe ) {
return new CorruptObjectException ( MessageFormat . format (
JGitText . get ( ) . packfileCorruptionDetected , dfe . getMessage ( ) ) ) ;
}
private static class DeltaChain extends ObjectId {
UnresolvedDelta head ;