| | class PackEntryReader { |
| | private const MAX_DEPTH = 200; |
| | - private const MAX_BASE_RAM = 1048576; |
| | + private const MAX_BASE_RAM = 8388608; |
| | private const MAX_CACHE = 1024; |
| | |
 |
| | $cur = $stream->tell(); |
| | $baseCtx = $context->deriveOffsetContext( $neg ); |
| | - $baseSz = $this->getSize( $baseCtx ); |
| | - |
| | - if( $baseSz > self::MAX_BASE_RAM ) { |
| | - $tmp = BufferedReader::createTemp(); |
| | |
| | - foreach( $this->streamEntryGenerator( $baseCtx ) as $chunk ) { |
| | - $tmp->write( $chunk ); |
| | - } |
| | + [ $base, $tmp ] = $this->collectBase( |
| | + $this->streamEntryGenerator( $baseCtx ) |
| | + ); |
| | |
| | - $tmp->rewind(); |
| | - $stream->seek( $cur ); |
| | + $stream->seek( $cur ); |
| | |
| | + if( $tmp !== null ) { |
| | yield from $this->decoder->applyStreamGenerator( $stream, $tmp ); |
| | } else { |
| | - $base = $this->read( |
| | - $baseCtx, |
| | - 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 ); |
| | } |
| | } |
| | |
| | private function processRefDelta( |
| | StreamReader $stream, |
| | PackContext $context |
| | ): Generator { |
| | - $baseSha = bin2hex( $stream->read( 20 ) ); |
| | - $cur = $stream->tell(); |
| | - $baseSize = $context->resolveBaseSize( $baseSha ); |
| | - |
| | - if( $baseSize > self::MAX_BASE_RAM ) { |
| | - $tmp = BufferedReader::createTemp(); |
| | - $add = false; |
| | - |
| | - foreach( $context->resolveBaseStream( $baseSha ) as $chunk ) { |
| | - $tmp->write( $chunk ); |
| | + $baseSha = bin2hex( $stream->read( 20 ) ); |
| | + $cur = $stream->tell(); |
| | + [ $base, $tmp ] = $this->collectBase( |
| | + $context->resolveBaseStream( $baseSha ) |
| | + ); |
| | |
| | - $add = true; |
| | - } |
| | + if( $base === '' && $tmp === null ) { |
| | + return; |
| | + } |
| | |
| | - if( $add ) { |
| | - $tmp->rewind(); |
| | - $stream->seek( $cur ); |
| | + $stream->seek( $cur ); |
| | |
| | - yield from $this->decoder->applyStreamGenerator( $stream, $tmp ); |
| | - } |
| | + if( $tmp !== null ) { |
| | + yield from $this->decoder->applyStreamGenerator( $stream, $tmp ); |
| | } else { |
| | - $chunks = []; |
| | - $add = false; |
| | + yield from $this->decoder->applyStreamGenerator( $stream, $base ); |
| | + } |
| | + } |
| | |
| | - foreach( $context->resolveBaseStream( $baseSha ) as $chunk ) { |
| | - $chunks[] = $chunk; |
| | + private function collectBase( iterable $chunks ): array { |
| | + $parts = []; |
| | + $total = 0; |
| | + $tmp = null; |
| | |
| | - $add = true; |
| | - } |
| | + foreach( $chunks as $chunk ) { |
| | + $total += strlen( $chunk ); |
| | |
| | - if( $add ) { |
| | - $base = implode( '', $chunks ); |
| | + if( $tmp !== null ) { |
| | + $tmp->write( $chunk ); |
| | + } elseif( $total > self::MAX_BASE_RAM ) { |
| | + $tmp = BufferedReader::createTemp(); |
| | |
| | - $stream->seek( $cur ); |
| | + foreach( $parts as $part ) { |
| | + $tmp->write( $part ); |
| | + } |
| | |
| | - yield from $this->decoder->applyStreamGenerator( $stream, $base ); |
| | + $tmp->write( $chunk ); |
| | + $parts = []; |
| | + } else { |
| | + $parts[] = $chunk; |
| | } |
| | + } |
| | + |
| | + if( $tmp !== null ) { |
| | + $tmp->rewind(); |
| | + |
| | + return [ '', $tmp ]; |
| | } |
| | + |
| | + return [ implode( '', $parts ), null ]; |
| | } |
| | |