| | |
| | class DeltaDecoder { |
| | + private const CHUNK_SIZE = 65536; |
| | + |
| | public function apply( string $base, string $delta, int $cap ): string { |
| | - $pos = 0; |
| | - $res = $this->readDeltaSize( $delta, $pos ); |
| | + $pos = 0; |
| | + $res = $this->readDeltaSize( $delta, $pos ); |
| | $pos += $res['used']; |
| | - $res = $this->readDeltaSize( $delta, $pos ); |
| | + $res = $this->readDeltaSize( $delta, $pos ); |
| | $pos += $res['used']; |
| | |
 |
| | $state = 0; |
| | $buffer = ''; |
| | + $offset = 0; |
| | $yieldBuffer = ''; |
| | $isFile = is_resource( $base ); |
| | |
| | foreach( $stream->stream( $handle ) as $data ) { |
| | + if( $offset > 0 ) { |
| | + $buffer = substr( $buffer, $offset ); |
| | + $offset = 0; |
| | + } |
| | + |
| | $buffer .= $data; |
| | $doneBuffer = false; |
| | |
| | while( !$doneBuffer ) { |
| | - $len = strlen( $buffer ); |
| | + $len = strlen( $buffer ) - $offset; |
| | |
| | if( $len === 0 ) { |
| | $doneBuffer = true; |
| | } |
| | |
| | if( !$doneBuffer ) { |
| | if( $state < 2 ) { |
| | - $pos = 0; |
| | + $pos = $offset; |
| | $found = false; |
| | |
| | - while( !$found && $pos < $len ) { |
| | + while( !$found && $pos < $offset + $len ) { |
| | if( !(ord( $buffer[$pos] ) & 128) ) { |
| | $found = true; |
| | } |
| | |
| | $pos++; |
| | } |
| | |
| | if( $found ) { |
| | - $buffer = substr( $buffer, $pos ); |
| | + $offset = $pos; |
| | $state++; |
| | } else { |
| | $doneBuffer = true; |
| | } |
| | } else { |
| | - $op = ord( $buffer[0] ); |
| | + $op = ord( $buffer[$offset] ); |
| | |
| | if( $op & 128 ) { |
| | $need = $this->calculateCopyInstructionSize( $op ); |
| | |
| | if( $len < 1 + $need ) { |
| | $doneBuffer = true; |
| | } |
| | |
| | if( !$doneBuffer ) { |
| | - $info = $this->parseCopyInstruction( $op, $buffer, 1 ); |
| | + $info = $this->parseCopyInstruction( |
| | + $op, |
| | + $buffer, |
| | + $offset + 1 |
| | + ); |
| | |
| | if( $isFile ) { |
| | fseek( $base, $info['off'] ); |
| | |
| | $rem = $info['len']; |
| | |
| | while( $rem > 0 ) { |
| | - $slc = fread( $base, min( 65536, $rem ) ); |
| | + $slc = fread( $base, min( self::CHUNK_SIZE, $rem ) ); |
| | |
| | if( $slc === false || $slc === '' ) { |
| | $rem = 0; |
| | } else { |
| | $yieldBuffer .= $slc; |
| | $rem -= strlen( $slc ); |
| | |
| | - if( strlen( $yieldBuffer ) >= 8192 ) { |
| | + if( strlen( $yieldBuffer ) >= self::CHUNK_SIZE ) { |
| | yield $yieldBuffer; |
| | |
| | $yieldBuffer = ''; |
| | } |
| | } |
| | } |
| | } else { |
| | $yieldBuffer .= substr( $base, $info['off'], $info['len'] ); |
| | |
| | - if( strlen( $yieldBuffer ) >= 8192 ) { |
| | + if( strlen( $yieldBuffer ) >= self::CHUNK_SIZE ) { |
| | yield $yieldBuffer; |
| | |
| | $yieldBuffer = ''; |
| | } |
| | } |
| | |
| | - $buffer = substr( $buffer, 1 + $need ); |
| | + $offset += 1 + $need; |
| | } |
| | } else { |
| | $ln = $op & 127; |
| | |
| | if( $len < 1 + $ln ) { |
| | $doneBuffer = true; |
| | } |
| | |
| | if( !$doneBuffer ) { |
| | - $yieldBuffer .= substr( $buffer, 1, $ln ); |
| | - $buffer = substr( $buffer, 1 + $ln ); |
| | + $yieldBuffer .= substr( $buffer, $offset + 1, $ln ); |
| | + $offset += 1 + $ln; |
| | |
| | - if( strlen( $yieldBuffer ) >= 8192 ) { |
| | + if( strlen( $yieldBuffer ) >= self::CHUNK_SIZE ) { |
| | yield $yieldBuffer; |
| | |