= $len) throw new GitException('壊れた差分'); $b = ord($delta[$pos++]); $n |= ($b & 0x7f) << $shift; $shift += 7; } while ($b & 0x80); return $n; } /** 差分を当てる */ public static function apply(string $base, string $delta): string { $pos = 0; $srcSize = self::size($delta, $pos); $dstSize = self::size($delta, $pos); if ($srcSize !== strlen($base)) throw new GitException('差分の元の大きさが違います'); $out = ''; $len = strlen($delta); while ($pos < $len) { $op = ord($delta[$pos++]); if ($op & 0x80) { // 元からコピー $off = 0; $size = 0; for ($i = 0; $i < 4; $i++) if ($op & (1 << $i)) $off |= ord($delta[$pos++]) << (8 * $i); for ($i = 0; $i < 3; $i++) if ($op & (0x10 << $i)) $size |= ord($delta[$pos++]) << (8 * $i); if ($size === 0) $size = 0x10000; if ($off + $size > $srcSize) throw new GitException('壊れた差分(範囲外)'); $out .= substr($base, $off, $size); } else if ($op > 0) { // そのまま挿入 if ($pos + $op > $len) throw new GitException('壊れた差分(短い)'); $out .= substr($delta, $pos, $op); $pos += $op; } else { throw new GitException('壊れた差分(不明な命令)'); } } if (strlen($out) !== $dstSize) throw new GitException('差分の結果の大きさが違います'); return $out; } /** 差分の結果の大きさ */ public static function targetSize(string $deltaHead): int { $pos = 0; self::size($deltaHead, $pos); return self::size($deltaHead, $pos); } }