72 if ( !function_exists(
'gzdeflate' ) ) {
73 throw new MWException(
"Need zlib support to read or write DiffHistoryBlob\n" );
83 if ( $this->mFrozen ) {
84 throw new MWException( __METHOD__ .
": Cannot add more items after sleep/wakeup" );
87 $this->mItems[] = $text;
88 $this->mSize += strlen( $text );
90 return count( $this->mItems ) - 1;
98 return $this->mItems[$key];
105 $this->mDefaultKey = $this->
addItem( $text );
112 return $this->
getItem( $this->mDefaultKey );
119 if ( !function_exists(
'xdiff_string_rabdiff' ) ) {
120 throw new MWException(
"Need xdiff 1.5+ support to write DiffHistoryBlob\n" );
122 if ( isset( $this->mDiffs ) ) {
126 if ( $this->mItems === [] ) {
145 $mItemsCount = count( $this->mItems );
146 for ( $i = 0; $i < $mItemsCount; $i++ ) {
147 $text = $this->mItems[$i];
151 $mainTail = $sequences[
'main'][
'tail'];
152 if ( strlen( $text ) < strlen( $mainTail ) * $smallFactor ) {
159 $tail = $sequences[$seqName][
'tail'];
160 $diff = $this->
diff( $tail, $text );
161 $sequences[$seqName][
'diffs'][] = $diff;
162 $sequences[$seqName][
'map'][] = $i;
163 $sequences[$seqName][
'tail'] = $text;
169 $this->mDiffMap = [];
170 foreach ( $sequences as $seq ) {
171 if ( $seq[
'diffs'] === [] ) {
174 if ( $tail ===
'' ) {
175 $this->mDiffs[] = $seq[
'diffs'][0];
177 $head = $this->
patch(
'', $seq[
'diffs'][0] );
178 $this->mDiffs[] = $this->
diff( $tail, $head );
180 $this->mDiffMap[] = $seq[
'map'][0];
181 $diffsCount = count( $seq[
'diffs'] );
182 for ( $i = 1; $i < $diffsCount; $i++ ) {
183 $this->mDiffs[] = $seq[
'diffs'][$i];
184 $this->mDiffMap[] = $seq[
'map'][$i];
186 $tail = $seq[
'tail'];
196 # Need to do a null concatenation with warnings off, due to bugs in the current version of xdiff
197 # "String is not zero-terminated"
198 Wikimedia\suppressWarnings();
199 $diff = xdiff_string_rabdiff( $t1, $t2 ) .
'';
200 Wikimedia\restoreWarnings();
210 if ( function_exists(
'xdiff_string_bpatch' ) ) {
211 Wikimedia\suppressWarnings();
212 $text = xdiff_string_bpatch(
$base, $diff ) .
'';
213 Wikimedia\restoreWarnings();
217 # Pure PHP implementation
219 $header = unpack(
'Vofp/Vcsize', substr( $diff, 0, 8 ) );
221 # Check the checksum if hash extension is available
223 if ( $ofp !==
false && $ofp !== substr( $diff, 0, 4 ) ) {
224 wfDebug( __METHOD__ .
": incorrect base checksum\n" );
228 wfDebug( __METHOD__ .
": incorrect base length\n" );
234 while ( $p < strlen( $diff ) ) {
235 $x = unpack(
'Cop', substr( $diff, $p, 1 ) );
240 $x = unpack(
'Csize', substr( $diff, $p, 1 ) );
242 $out .= substr( $diff, $p, $x[
'size'] );
246 $x = unpack(
'Vcsize', substr( $diff, $p, 4 ) );
248 $out .= substr( $diff, $p, $x[
'csize'] );
252 $x = unpack(
'Voff/Vcsize', substr( $diff, $p, 8 ) );
254 $out .= substr(
$base, $x[
'off'], $x[
'csize'] );
257 wfDebug( __METHOD__ .
": invalid op\n" );
272 if ( !function_exists(
'hash' ) ) {
277 if ( $init ===
null ) {
278 $init = str_repeat(
"\xf0", 205 ) .
"\xee" . str_repeat(
"\xf0", 67 ) .
"\x02";
284 return strrev( hash(
'adler32', $init .
$s,
true ) );
288 if ( !$this->mDiffs ) {
292 $mDiffsCount = count( $this->mDiffs );
293 for ( $diffKey = 0; $diffKey < $mDiffsCount; $diffKey++ ) {
294 $textKey = $this->mDiffMap[$diffKey];
295 $text = $this->
patch( $tail, $this->mDiffs[$diffKey] );
296 $this->mItems[$textKey] = $text;
306 if ( $this->mItems === [] ) {
312 foreach ( $this->mDiffMap as $i ) {
324 if ( isset( $this->mDefaultKey ) ) {
327 $this->mCompressed = gzdeflate(
serialize( $info ) );
328 return [
'mCompressed' ];
333 $this->mFrozen =
true;
334 $info =
unserialize( gzinflate( $this->mCompressed ) );
335 $this->mCompressed =
null;
342 if ( isset( $info[
'default'] ) ) {
343 $this->mDefaultKey = $info[
'default'];
345 $this->mDiffs = $info[
'diffs'];
346 if ( isset( $info[
'base'] ) ) {
348 $this->mDiffMap = range( 0, count( $this->mDiffs ) - 1 );
349 array_unshift( $this->mDiffs,
350 pack(
'VVCV', 0, 0, self::XDL_BDOP_INSB, strlen( $info[
'base'] ) ) .
354 $map = explode(
',', $info[
'map'] );
356 $this->mDiffMap = [];
357 foreach ( $map as $i ) {
359 $this->mDiffMap[] = $cur;
372 return $this->mSize < $this->mMaxSize