7 public function __construct($source) {
8 $this->source = $source;
11 public function createPatch($target, $metadata = '') {
12 $this->target = $target;
14 $this->sourceCursor = 0;
15 $this->targetCursor = 0;
17 $this->writeString('BPS1');
18 $this->writeNumber(strlen($this->source));
19 $this->writeNumber(strlen($this->target));
20 $this->writeNumber(strlen($metadata));
21 $this->writeString($metadata);
25 while ($this->targetCursor < strlen($this->target)) {
27 while ($this->sourceLeft($numUnchanged) && $this->sourceEqual($numUnchanged, $numUnchanged, 1)) {
30 if ($numUnchanged > 1 || $numUnchanged == (strlen($this->target) - $this->targetCursor)) {
31 $this->writeNumber(($numUnchanged - 1) << 2);
32 $this->sourceCursor += $numUnchanged;
33 $this->targetCursor += $numUnchanged;
37 if ($lastKnownChange > $this->targetCursor) {
38 $numChanged = $lastKnownChange - $this->targetCursor;
40 while ((!$this->sourceLeft($numChanged) || !$this->sourceEqual($numChanged, $numChanged, 3))
41 && $this->targetLeft($numChanged)
44 if (!$this->sourceLeft($numChanged)) {
45 $numChanged = strlen($this->target) - $this->targetCursor;
48 $lastKnownChange = $this->targetCursor + $numChanged;
50 $rle1Start = $this->targetCursor == 0 ? 1 : 0;
52 if ($this->targetEqual($rle1Start - 1, $rle1Start, 4)
53 || $this->targetEqual($rle1Start - 2, $rle1Start, 5)
55 $numChanged = $rle1Start;
58 if ($rle1Start + 3 > $numChanged) {
64 $this->writeNumber(($numChanged - 1) << 2 | 1);
65 $this->writeString(substr($this->target, $this->targetCursor, $numChanged));
66 $this->sourceCursor += $numChanged;
67 $this->targetCursor += $numChanged;
69 if ($this->targetEqual(-2, 0, 3)) {
71 while ($this->targetLeft($rleLen) && $this->targetEqual(0, $rleLen, 2)) {
74 $this->writeNumber(($rleLen - 1) << 2 | 3);
75 $this->writeNumber(($this->targetCursor - $targetCopyPos - 2) << 1);
76 $this->sourceCursor += $rleLen;
77 $this->targetCursor += $rleLen;
78 $targetCopyPos = $this->targetCursor - 2;
79 } else if ($this->targetEqual(-1, 0, 2)) {
81 while ($this->targetLeft($rleLen) && $this->targetEqual(0, $rleLen, 1)) {
84 $this->writeNumber(($rleLen - 1) << 2 | 3);
85 $this->writeNumber(($this->targetCursor - $targetCopyPos - 1) << 1);
86 $this->sourceCursor += $rleLen;
87 $this->targetCursor += $rleLen;
88 $targetCopyPos = $this->targetCursor - 1;
93 $this->write32(crc32($this->source));
94 $this->write32(crc32($this->target));
95 $this->write32(crc32($this->patch));
101 private function sourceChar($offset = 0) {
102 return $this->source[$this->sourceCursor + $offset];
105 private function sourceEqual($aOff, $bOff, $len) {
106 $aStr = substr($this->source, $this->sourceCursor + $aOff, $len);
107 $bStr = substr($this->target, $this->targetCursor + $bOff, $len);
108 return $aStr == $bStr;
111 private function sourceLeft($num) {
112 return $this->sourceCursor + $num < strlen($this->source);
115 private function targetChar($offset = 0) {
116 return $this->target[$this->targetCursor + $offset];
119 private function targetEqual($aOff, $bOff, $len) {
120 $aStr = substr($this->target, $this->targetCursor + $aOff, $len);
121 $bStr = substr($this->target, $this->targetCursor + $bOff, $len);
122 return $aStr == $bStr;
125 private function targetLeft($num) {
126 return $this->targetCursor + $num < strlen($this->target);
130 private function write32($val) {
131 $this->writeByte($val & 0xFF);
132 $this->writeByte(($val >> 8) & 0xFF);
133 $this->writeByte(($val >> 16) & 0xFF);
134 $this->writeByte(($val >> 24) & 0xFF);
137 private function writeByte($val) {
138 $this->patch .= chr($val);
141 private function writeNumber($val) {
143 for ($i = 0; $i < 16; ++$i) {
144 $tmpbyte = $tmpval & 0x7f;
147 $this->writeByte($tmpbyte | 0x80);
150 $this->writeByte($tmpbyte);
155 private function writeString($str) {
156 $this->patch .= $str;
161 private $target = '';
164 private $sourceCursor = 0;
165 private $targetCursor = 0;