| | } |
| | |
| | - $compressed = fread( $fileHandle, self::MAX_READ ); |
| | - $delta = @gzuncompress( $compressed ) ?: ''; |
| | + $inflator = inflate_init( ZLIB_ENCODING_DEFLATE ); |
| | |
| | - $result = $this->applyDelta( $base, $delta ); |
| | + if( $inflator === false ) { |
| | + return false; |
| | + } |
| | |
| | - $chunkSize = 8192; |
| | - $length = strlen( $result ); |
| | + // 0: source size, 1: target size, 2: opcodes |
| | + $headerState = 0; |
| | + $buffer = ''; |
| | |
| | - for( $i = 0; $i < $length; $i += $chunkSize ) { |
| | - $callback( substr( $result, $i, $chunkSize ) ); |
| | + while( !feof( $fileHandle ) ) { |
| | + // Read small chunks to prevent memory spikes |
| | + $chunk = fread( $fileHandle, 8192 ); |
| | + |
| | + if( $chunk === false || $chunk === '' ) { |
| | + break; |
| | + } |
| | + |
| | + $data = @inflate_add( $inflator, $chunk ); |
| | + |
| | + if( $data === false ) { |
| | + break; |
| | + } |
| | + |
| | + $buffer .= $data; |
| | + |
| | + // Process the buffer |
| | + while( true ) { |
| | + $bufLen = strlen( $buffer ); |
| | + |
| | + if( $bufLen === 0 ) { |
| | + break; |
| | + } |
| | + |
| | + if( $headerState < 2 ) { |
| | + $pos = 0; |
| | + |
| | + while( $pos < $bufLen && (ord( $buffer[$pos] ) & 128) ) { |
| | + $pos++; |
| | + } |
| | + |
| | + if( $pos === $bufLen && (ord( $buffer[$pos - 1] ) & 128) ) { |
| | + break; |
| | + } |
| | + |
| | + $pos++; |
| | + $buffer = substr( $buffer, $pos ); |
| | + $headerState++; |
| | + continue; |
| | + } |
| | + |
| | + $opcode = ord( $buffer[0] ); |
| | + |
| | + if( $opcode & 128 ) { |
| | + $needed = 1; |
| | + if( $opcode & 0x01 ) { $needed++; } |
| | + if( $opcode & 0x02 ) { $needed++; } |
| | + if( $opcode & 0x04 ) { $needed++; } |
| | + if( $opcode & 0x08 ) { $needed++; } |
| | + if( $opcode & 0x10 ) { $needed++; } |
| | + if( $opcode & 0x20 ) { $needed++; } |
| | + if( $opcode & 0x40 ) { $needed++; } |
| | + |
| | + if( $bufLen < $needed ) { |
| | + break; |
| | + } |
| | + |
| | + $off = 0; |
| | + $len = 0; |
| | + $p = 1; |
| | + |
| | + if( $opcode & 0x01 ) { $off |= ord( $buffer[$p++] ); } |
| | + if( $opcode & 0x02 ) { $off |= ord( $buffer[$p++] ) << 8; } |
| | + if( $opcode & 0x04 ) { $off |= ord( $buffer[$p++] ) << 16; } |
| | + if( $opcode & 0x08 ) { $off |= ord( $buffer[$p++] ) << 24; } |
| | + |
| | + if( $opcode & 0x10 ) { $len |= ord( $buffer[$p++] ); } |
| | + if( $opcode & 0x20 ) { $len |= ord( $buffer[$p++] ) << 8; } |
| | + if( $opcode & 0x40 ) { $len |= ord( $buffer[$p++] ) << 16; } |
| | + |
| | + if( $len === 0 ) { $len = 0x10000; } |
| | + |
| | + $callback( substr( $base, $off, $len ) ); |
| | + $buffer = substr( $buffer, $needed ); |
| | + |
| | + } else { |
| | + $len = $opcode & 127; |
| | + |
| | + if( $bufLen < 1 + $len ) { |
| | + break; |
| | + } |
| | + |
| | + $callback( substr( $buffer, 1, $len ) ); |
| | + $buffer = substr( $buffer, 1 + $len ); |
| | + } |
| | + } |
| | + |
| | + if( inflate_get_status( $inflator ) === ZLIB_STREAM_END ) { |
| | + break; |
| | + } |
| | } |
| | |
| | return true; |
| | } |
| | |
| | - private function streamDecompression( $fileHandle, callable $callback ): bool { |
| | + private function streamDecompression( |
| | + $fileHandle, |
| | + callable $callback |
| | + ): bool { |
| | $inflator = inflate_init( ZLIB_ENCODING_DEFLATE ); |
| | |