| | } |
| | |
| | - private function getPackedObjectSize(string $sha): int { |
| | +private function getPackedObjectSize(string $sha): int { |
| | $info = $this->getPackOffset($sha); |
| | if (!$info) return 0; |
 |
| | $size = $byte & 15; |
| | $shift = 4; |
| | + |
| | while ($byte & 128) { |
| | $byte = ord(fread($pf, 1)); |
| | $size |= (($byte & 127) << $shift); |
| | $shift += 7; |
| | } |
| | |
| | - if ($type === 6 || $type === 7) { |
| | - if ($type === 6) { // OFS_DELTA |
| | - $byte = ord(fread($pf, 1)); |
| | - while ($byte & 128) { $byte = ord(fread($pf, 1)); } |
| | - } else { // REF_DELTA |
| | - fread($pf, 20); |
| | - } |
| | + // If the object is not a delta, the size we just read is the final size. |
| | + if ($type !== 6 && $type !== 7) { |
| | + fclose($pf); |
| | + return $size; |
| | + } |
| | |
| | - $ctx = inflate_init(ZLIB_ENCODING_DEFLATE); |
| | - $buffer = ''; |
| | - $found = false; |
| | - while (!$found && !feof($pf)) { |
| | - $chunk = fread($pf, 512); |
| | - $inflated = @inflate_add($ctx, $chunk, ZLIB_NO_FLUSH); |
| | - if ($inflated === false) { fclose($pf); return 0; } |
| | - $buffer .= $inflated; |
| | - if (strlen($buffer) > 32) $found = true; |
| | - } |
| | + // For Deltas (Type 6 or 7), the 'size' above is the size of the delta data, |
| | + // not the resulting file. We must find the "Target Size" inside the delta header. |
| | + if ($type === 6) { // OFS_DELTA: skip the negative offset |
| | + $byte = ord(fread($pf, 1)); |
| | + while ($byte & 128) { $byte = ord(fread($pf, 1)); } |
| | + } else { // REF_DELTA: skip the 20-byte base SHA |
| | + fread($pf, 20); |
| | + } |
| | |
| | - $pos = 0; |
| | - // Skip Source Size |
| | - if (!isset($buffer[$pos])) { fclose($pf); return 0; } |
| | - $byte = ord($buffer[$pos++]); |
| | - while ($byte & 128) { |
| | - if (!isset($buffer[$pos])) break; |
| | - $byte = ord($buffer[$pos++]); |
| | - } |
| | - // Read Target Size |
| | - if (!isset($buffer[$pos])) { fclose($pf); return 0; } |
| | - $byte = ord($buffer[$pos++]); |
| | - $size = $byte & 127; |
| | - $shift = 7; |
| | - while ($byte & 128) { |
| | - if (!isset($buffer[$pos])) break; |
| | - $byte = ord($buffer[$pos++]); |
| | - $size |= (($byte & 127) << $shift); |
| | - $shift += 7; |
| | - } |
| | + // Inflate only the beginning of the delta data to get the header |
| | + $ctx = inflate_init(ZLIB_ENCODING_DEFLATE); |
| | + $headerData = ''; |
| | + while (!feof($pf)) { |
| | + $chunk = fread($pf, 512); |
| | + $inflated = @inflate_add($ctx, $chunk, ZLIB_NO_FLUSH); |
| | + if ($inflated !== false) $headerData .= $inflated; |
| | + if (strlen($headerData) >= 32) break; // We usually only need ~10 bytes |
| | } |
| | fclose($pf); |
| | - return $size; |
| | + |
| | + if (strlen($headerData) === 0) return 0; |
| | + |
| | + $pos = 0; |
| | + // 1. Skip Source Size (Base Object Size) |
| | + $byte = ord($headerData[$pos++]); |
| | + while ($byte & 128 && $pos < strlen($headerData)) { |
| | + $byte = ord($headerData[$pos++]); |
| | + } |
| | + |
| | + // 2. Read Target Size (The actual file size we want to display) |
| | + if ($pos >= strlen($headerData)) return 0; |
| | + $byte = ord($headerData[$pos++]); |
| | + $targetSize = $byte & 127; |
| | + $shift = 7; |
| | + while ($byte & 128 && $pos < strlen($headerData)) { |
| | + $byte = ord($headerData[$pos++]); |
| | + $targetSize |= (($byte & 127) << $shift); |
| | + $shift += 7; |
| | + } |
| | + |
| | + return $targetSize; |
| | } |
| | |