| | $header = $this->readVarInt( $stream ); |
| | $type = $header['byte'] >> 4 & 7; |
| | + $gen = []; |
| | |
| | if( $type !== 6 && $type !== 7 ) { |
| | - $extractor = CompressionStream::createExtractor(); |
| | - |
| | - yield from $extractor->stream( $stream ); |
| | + $gen = CompressionStream::createExtractor()->stream( $stream ); |
| | } |
| | + |
| | + yield from $gen; |
| | } |
| | ); |
 |
| | $header = $this->readVarInt( $stream ); |
| | $type = $header['byte'] >> 4 & 7; |
| | - |
| | - if( $type === 6 || $type === 7 ) { |
| | - yield from $this->streamDeltaObjectGenerator( |
| | - $stream, |
| | - $context, |
| | - $type |
| | - ); |
| | - } else { |
| | - $inflater = CompressionStream::createInflater(); |
| | + $gen = $type === 6 || $type === 7 |
| | + ? $this->streamDeltaObjectGenerator( |
| | + $stream, |
| | + $context, |
| | + $type, |
| | + $offset |
| | + ) |
| | + : CompressionStream::createInflater()->stream( $stream ); |
| | |
| | - yield from $inflater->stream( $stream ); |
| | - } |
| | + yield from $gen; |
| | } |
| | ); |
| | } |
| | |
| | private function streamDeltaObjectGenerator( |
| | StreamReader $stream, |
| | PackContext $context, |
| | - int $type |
| | + int $type, |
| | + int $offset |
| | ): Generator { |
| | + $gen = []; |
| | + |
| | if( $context->isWithinDepth( self::MAX_DEPTH ) ) { |
| | - if( $type === 6 ) { |
| | - yield from $this->processOffsetDelta( $stream, $context ); |
| | - } else { |
| | - yield from $this->processRefDelta( $stream, $context ); |
| | - } |
| | + $gen = $type === 6 |
| | + ? $this->processOffsetDelta( $stream, $context, $offset ) |
| | + : $this->processRefDelta( $stream, $context ); |
| | + } |
| | + |
| | + yield from $gen; |
| | + } |
| | + |
| | + private function readSizeWithStream( |
| | + StreamReader $stream, |
| | + int $offset |
| | + ): int { |
| | + $cur = $stream->tell(); |
| | + |
| | + $stream->seek( $offset ); |
| | + |
| | + $header = $this->readVarInt( $stream ); |
| | + $size = $header['value']; |
| | + $type = $header['byte'] >> 4 & 7; |
| | + |
| | + if( $type === 6 || $type === 7 ) { |
| | + $size = $this->decoder->readDeltaTargetSize( $stream, $type ); |
| | } |
| | + |
| | + $stream->seek( $cur ); |
| | + |
| | + return $size; |
| | } |
| | |
| | private function processOffsetDelta( |
| | StreamReader $stream, |
| | - PackContext $context |
| | + PackContext $context, |
| | + int $offset |
| | ): Generator { |
| | $neg = $this->readOffsetDelta( $stream ); |
| | $cur = $stream->tell(); |
| | - $baseCtx = $context->deriveOffsetContext( $neg ); |
| | + $baseOff = $offset - $neg; |
| | + $size = $this->readSizeWithStream( $stream, $baseOff ); |
| | + $baseSrc = ''; |
| | |
| | - if( $this->getSize( $baseCtx ) <= self::MAX_BASE_RAM ) { |
| | - $base = $this->read( |
| | - $baseCtx, |
| | + if( $size <= self::MAX_BASE_RAM ) { |
| | + $baseSrc = $this->readWithStream( |
| | + $stream, |
| | + $baseOff, |
| | 0, |
| | function( string $sha, int $cap ) use ( $context ): string { |
| | return $this->resolveBaseSha( $sha, $cap, $context ); |
| | } |
| | ); |
| | - |
| | - $stream->seek( $cur ); |
| | - yield from $this->decoder->applyStreamGenerator( $stream, $base ); |
| | } else { |
| | - [ $base, $tmp ] = $this->collectBase( |
| | + $baseCtx = $context->deriveOffsetContext( $neg ); |
| | + [ $b, $tmp ] = $this->collectBase( |
| | $this->streamEntryGenerator( $baseCtx ) |
| | ); |
| | + $baseSrc = $tmp instanceof BufferedReader ? $tmp : $b; |
| | + } |
| | |
| | - $stream->seek( $cur ); |
| | + $stream->seek( $cur ); |
| | |
| | - if( $tmp !== null ) { |
| | - yield from $this->decoder->applyStreamGenerator( $stream, $tmp ); |
| | - } else { |
| | - yield from $this->decoder->applyStreamGenerator( $stream, $base ); |
| | - } |
| | - } |
| | + yield from $this->decoder->applyStreamGenerator( $stream, $baseSrc ); |
| | } |
| | |
| | private function processRefDelta( |
| | StreamReader $stream, |
| | PackContext $context |
| | ): Generator { |
| | $baseSha = \bin2hex( $stream->read( 20 ) ); |
| | $cur = $stream->tell(); |
| | - |
| | - if( $context->resolveBaseSize( $baseSha ) <= self::MAX_BASE_RAM ) { |
| | - $base = $this->resolveBaseSha( $baseSha, 0, $context ); |
| | + $size = $context->resolveBaseSize( $baseSha ); |
| | + $baseSrc = ''; |
| | |
| | - $stream->seek( $cur ); |
| | - yield from $this->decoder->applyStreamGenerator( $stream, $base ); |
| | + if( $size <= self::MAX_BASE_RAM ) { |
| | + $baseSrc = $this->resolveBaseSha( $baseSha, 0, $context ); |
| | } else { |
| | - [ $base, $tmp ] = $this->collectBase( |
| | + [ $b, $tmp ] = $this->collectBase( |
| | $context->resolveBaseStream( $baseSha ) |
| | ); |
| | + $baseSrc = $tmp instanceof BufferedReader ? $tmp : $b; |
| | + } |
| | |
| | - if( $base !== '' || $tmp !== null ) { |
| | - $stream->seek( $cur ); |
| | + $stream->seek( $cur ); |
| | |
| | - if( $tmp !== null ) { |
| | - yield from $this->decoder->applyStreamGenerator( $stream, $tmp ); |
| | - } else { |
| | - yield from $this->decoder->applyStreamGenerator( $stream, $base ); |
| | - } |
| | - } |
| | - } |
| | + yield from $this->decoder->applyStreamGenerator( $stream, $baseSrc ); |
| | } |
| | |
| | private function collectBase( iterable $chunks ): array { |
| | $parts = []; |
| | $total = 0; |
| | - $tmp = null; |
| | + $tmp = false; |
| | |
| | foreach( $chunks as $chunk ) { |
| | $total += \strlen( $chunk ); |
| | |
| | - if( $tmp !== null ) { |
| | + if( $tmp instanceof BufferedReader ) { |
| | $tmp->write( $chunk ); |
| | } elseif( $total > self::MAX_BASE_RAM ) { |
 |
| | } |
| | |
| | - if( $tmp !== null ) { |
| | + if( $tmp instanceof BufferedReader ) { |
| | $tmp->rewind(); |
| | } |
| | |
| | - return [ $tmp === null ? \implode( '', $parts ) : '', $tmp ]; |
| | + return [ $tmp === false ? \implode( '', $parts ) : '', $tmp ]; |
| | } |
| | |