80 if ( !function_exists(
'gzdeflate' ) ) {
81 throw new MWException(
"Need zlib support to read or write this "
82 .
"kind of history object (ConcatenatedGzipHistoryBlob)\n" );
93 if ( !isset( $this->mItems[$hash] ) ) {
94 $this->mItems[$hash] = $text;
95 $this->mSize += strlen( $text );
106 if ( array_key_exists( $hash, $this->mItems ) ) {
107 return $this->mItems[$hash];
119 $this->mDefaultHash = $this->
addItem( $text );
127 return $this->
getItem( $this->mDefaultHash );
136 $this->mSize -= strlen( $this->mItems[$hash] );
137 unset( $this->mItems[$hash] );
144 if ( !$this->mCompressed ) {
145 $this->mItems = gzdeflate(
serialize( $this->mItems ) );
146 $this->mCompressed =
true;
154 if ( $this->mCompressed ) {
155 $this->mItems =
unserialize( gzinflate( $this->mItems ) );
156 $this->mCompressed =
false;
165 return [
'mVersion',
'mCompressed',
'mItems',
'mDefaultHash' ];
179 return $this->mSize < $this->mMaxSize
210 $this->mHash = $hash;
242 if ( isset( self::$blobCache[$this->mOldId] ) ) {
246 $row =
$dbr->selectRow(
248 [
'old_flags',
'old_text' ],
249 [
'old_id' => $this->mOldId ]
256 $flags = explode(
',', $row->old_flags );
257 if ( in_array(
'external', $flags ) ) {
258 $url = $row->old_text;
259 $parts = explode(
'://', $url, 2 );
260 if ( !isset( $parts[1] ) || $parts[1] ==
'' ) {
267 if ( !in_array(
'object', $flags ) ) {
271 if ( in_array(
'gzip', $flags ) ) {
279 if ( !is_object( $obj ) ) {
287 self::$blobCache = [ $this->mOldId => $obj ];
290 return $obj->getItem( $this->mHash );
319 $this->mCurId = $curid;
337 $row =
$dbr->selectRow(
'cur', [
'cur_text' ], [
'cur_id' => $this->mCurId ] );
341 return $row->cur_text;
394 if ( !function_exists(
'gzdeflate' ) ) {
395 throw new MWException(
"Need zlib support to read or write DiffHistoryBlob\n" );
405 if ( $this->mFrozen ) {
406 throw new MWException( __METHOD__ .
": Cannot add more items after sleep/wakeup" );
409 $this->mItems[] = $text;
410 $this->mSize += strlen( $text );
411 $this->mDiffs =
null;
412 return count( $this->mItems ) - 1;
420 return $this->mItems[$key];
427 $this->mDefaultKey = $this->
addItem( $text );
434 return $this->
getItem( $this->mDefaultKey );
441 if ( !function_exists(
'xdiff_string_rabdiff' ) ) {
442 throw new MWException(
"Need xdiff 1.5+ support to write DiffHistoryBlob\n" );
444 if ( isset( $this->mDiffs ) ) {
448 if ( !
count( $this->mItems ) ) {
468 $mItemsCount =
count( $this->mItems );
469 for ( $i = 0; $i < $mItemsCount; $i++ ) {
470 $text = $this->mItems[$i];
474 $mainTail = $sequences[
'main'][
'tail'];
475 if ( strlen( $text ) < strlen( $mainTail ) * $smallFactor ) {
481 $seq =& $sequences[$seqName];
482 $tail = $seq[
'tail'];
483 $diff = $this->
diff( $tail, $text );
484 $seq[
'diffs'][] = $diff;
486 $seq[
'tail'] = $text;
493 $this->mDiffMap = [];
494 foreach ( $sequences
as $seq ) {
495 if ( !
count( $seq[
'diffs'] ) ) {
498 if ( $tail ===
'' ) {
499 $this->mDiffs[] = $seq[
'diffs'][0];
501 $head = $this->
patch(
'', $seq[
'diffs'][0] );
502 $this->mDiffs[] = $this->
diff( $tail, $head );
504 $this->mDiffMap[] = $seq[
'map'][0];
505 $diffsCount =
count( $seq[
'diffs'] );
506 for ( $i = 1; $i < $diffsCount; $i++ ) {
507 $this->mDiffs[] = $seq[
'diffs'][$i];
508 $this->mDiffMap[] = $seq[
'map'][$i];
510 $tail = $seq[
'tail'];
520 # Need to do a null concatenation with warnings off, due to bugs in the current version of xdiff
521 # "String is not zero-terminated"
522 Wikimedia\suppressWarnings();
523 $diff = xdiff_string_rabdiff( $t1, $t2 ) .
'';
524 Wikimedia\restoreWarnings();
534 if ( function_exists(
'xdiff_string_bpatch' ) ) {
535 Wikimedia\suppressWarnings();
536 $text = xdiff_string_bpatch(
$base, $diff ) .
'';
537 Wikimedia\restoreWarnings();
541 # Pure PHP implementation
543 $header = unpack(
'Vofp/Vcsize', substr( $diff, 0, 8 ) );
545 # Check the checksum if hash extension is available
547 if ( $ofp !==
false && $ofp !== substr( $diff, 0, 4 ) ) {
548 wfDebug( __METHOD__ .
": incorrect base checksum\n" );
552 wfDebug( __METHOD__ .
": incorrect base length\n" );
558 while ( $p < strlen( $diff ) ) {
559 $x = unpack(
'Cop', substr( $diff, $p, 1 ) );
564 $x = unpack(
'Csize', substr( $diff, $p, 1 ) );
566 $out .= substr( $diff, $p, $x[
'size'] );
570 $x = unpack(
'Vcsize', substr( $diff, $p, 4 ) );
572 $out .= substr( $diff, $p, $x[
'csize'] );
576 $x = unpack(
'Voff/Vcsize', substr( $diff, $p, 8 ) );
578 $out .= substr(
$base, $x[
'off'], $x[
'csize'] );
581 wfDebug( __METHOD__ .
": invalid op\n" );
596 if ( !function_exists(
'hash' ) ) {
601 if ( $init ===
null ) {
602 $init = str_repeat(
"\xf0", 205 ) .
"\xee" . str_repeat(
"\xf0", 67 ) .
"\x02";
608 return strrev( hash(
'adler32', $init .
$s,
true ) );
612 if ( !$this->mDiffs ) {
616 $mDiffsCount =
count( $this->mDiffs );
617 for ( $diffKey = 0; $diffKey < $mDiffsCount; $diffKey++ ) {
618 $textKey = $this->mDiffMap[$diffKey];
619 $text = $this->
patch( $tail, $this->mDiffs[$diffKey] );
620 $this->mItems[$textKey] = $text;
630 if ( !
count( $this->mItems ) ) {
637 foreach ( $this->mDiffMap
as $i ) {
649 if ( isset( $this->mDefaultKey ) ) {
652 $this->mCompressed = gzdeflate(
serialize( $info ) );
653 return [
'mCompressed' ];
658 $this->mFrozen =
true;
659 $info =
unserialize( gzinflate( $this->mCompressed ) );
660 unset( $this->mCompressed );
667 if ( isset( $info[
'default'] ) ) {
668 $this->mDefaultKey = $info[
'default'];
670 $this->mDiffs = $info[
'diffs'];
671 if ( isset( $info[
'base'] ) ) {
673 $this->mDiffMap = range( 0,
count( $this->mDiffs ) - 1 );
674 array_unshift( $this->mDiffs,
675 pack(
'VVCV', 0, 0, self::XDL_BDOP_INSB, strlen( $info[
'base'] ) ) .
679 $map = explode(
',', $info[
'map'] );
681 $this->mDiffMap = [];
682 foreach ( $map
as $i ) {
684 $this->mDiffMap[] = $cur;
697 return $this->mSize < $this->mMaxSize