85 if ( !function_exists(
'gzdeflate' ) ) {
86 throw new MWException(
"Need zlib support to read or write this kind of history object (ConcatenatedGzipHistoryBlob)\n" );
97 if ( !isset( $this->mItems[
$hash] ) ) {
98 $this->mItems[
$hash] = $text;
99 $this->mSize += strlen( $text );
110 if ( array_key_exists(
$hash, $this->mItems ) ) {
111 return $this->mItems[
$hash];
123 $this->mDefaultHash = $this->
addItem( $text );
131 return $this->
getItem( $this->mDefaultHash );
140 $this->mSize -= strlen( $this->mItems[
$hash] );
141 unset( $this->mItems[
$hash] );
148 if ( !$this->mCompressed ) {
149 $this->mItems = gzdeflate( serialize( $this->mItems ) );
150 $this->mCompressed =
true;
158 if ( $this->mCompressed ) {
159 $this->mItems = unserialize( gzinflate( $this->mItems ) );
160 $this->mCompressed =
false;
169 return array(
'mVersion',
'mCompressed',
'mItems',
'mDefaultHash' );
183 return $this->mSize < $this->mMaxSize
207 $this->mHash =
$hash;
236 if ( isset( self::$blobCache[$this->mOldId] ) ) {
240 $row =
$dbr->selectRow(
'text',
array(
'old_flags',
'old_text' ),
array(
'old_id' => $this->mOldId ) );
244 $flags = explode(
',', $row->old_flags );
245 if ( in_array(
'external',
$flags ) ) {
246 $url = $row->old_text;
247 $parts = explode(
'://', $url, 2 );
248 if ( !isset( $parts[1] ) || $parts[1] ==
'' ) {
251 $row->old_text = ExternalStore::fetchFromUrl( $url );
254 if ( !in_array(
'object',
$flags ) ) {
258 if ( in_array(
'gzip',
$flags ) ) {
261 $obj = unserialize( gzinflate( $row->old_text ) );
263 $obj = unserialize( $row->old_text );
266 if ( !is_object( $obj ) ) {
268 $obj = unserialize( $obj );
274 self::$blobCache =
array( $this->mOldId => $obj );
276 return $obj->getItem( $this->mHash );
304 $this->mCurId = $curid;
322 $row =
$dbr->selectRow(
'cur',
array(
'cur_text' ),
array(
'cur_id' => $this->mCurId ) );
326 return $row->cur_text;
386 if ( !function_exists(
'gzdeflate' ) ) {
387 throw new MWException(
"Need zlib support to read or write DiffHistoryBlob\n" );
397 if ( $this->mFrozen ) {
398 throw new MWException( __METHOD__ .
": Cannot add more items after sleep/wakeup" );
401 $this->mItems[] = $text;
402 $this->mSize += strlen( $text );
403 $this->mDiffs =
null;
404 return count( $this->mItems ) - 1;
412 return $this->mItems[$key];
419 $this->mDefaultKey = $this->
addItem( $text );
426 return $this->
getItem( $this->mDefaultKey );
433 if ( !function_exists(
'xdiff_string_rabdiff' ) ) {
434 throw new MWException(
"Need xdiff 1.5+ support to write DiffHistoryBlob\n" );
436 if ( isset( $this->mDiffs ) ) {
440 if ( !count( $this->mItems ) ) {
460 for ( $i = 0; $i < count( $this->mItems ); $i++ ) {
461 $text = $this->mItems[$i];
465 $mainTail = $sequences[
'main'][
'tail'];
466 if ( strlen( $text ) < strlen( $mainTail ) * $smallFactor ) {
472 $seq =& $sequences[$seqName];
473 $tail = $seq[
'tail'];
474 $diff = $this->
diff( $tail, $text );
475 $seq[
'diffs'][] = $diff;
477 $seq[
'tail'] = $text;
483 $this->mDiffs =
array();
484 $this->mDiffMap =
array();
485 foreach ( $sequences
as $seq ) {
486 if ( !count( $seq[
'diffs'] ) ) {
489 if ( $tail ===
'' ) {
490 $this->mDiffs[] = $seq[
'diffs'][0];
492 $head = $this->
patch(
'', $seq[
'diffs'][0] );
493 $this->mDiffs[] = $this->
diff( $tail, $head );
495 $this->mDiffMap[] = $seq[
'map'][0];
496 for ( $i = 1; $i < count( $seq[
'diffs'] ); $i++ ) {
497 $this->mDiffs[] = $seq[
'diffs'][$i];
498 $this->mDiffMap[] = $seq[
'map'][$i];
500 $tail = $seq[
'tail'];
510 # Need to do a null concatenation with warnings off, due to bugs in the current version of xdiff
511 # "String is not zero-terminated"
513 $diff = xdiff_string_rabdiff( $t1, $t2 ) .
'';
524 if ( function_exists(
'xdiff_string_bpatch' ) ) {
526 $text = xdiff_string_bpatch( $base, $diff ) .
'';
531 # Pure PHP implementation
533 $header = unpack(
'Vofp/Vcsize', substr( $diff, 0, 8 ) );
535 # Check the checksum if hash extension is available
537 if ( $ofp !==
false && $ofp !== substr( $diff, 0, 4 ) ) {
538 wfDebug( __METHOD__ .
": incorrect base checksum\n" );
541 if ( $header[
'csize'] != strlen( $base ) ) {
542 wfDebug( __METHOD__ .
": incorrect base length\n" );
548 while ( $p < strlen( $diff ) ) {
549 $x = unpack(
'Cop', substr( $diff, $p, 1 ) );
554 $x = unpack(
'Csize', substr( $diff, $p, 1 ) );
556 $out .= substr( $diff, $p, $x[
'size'] );
560 $x = unpack(
'Vcsize', substr( $diff, $p, 4 ) );
562 $out .= substr( $diff, $p, $x[
'csize'] );
566 $x = unpack(
'Voff/Vcsize', substr( $diff, $p, 8 ) );
568 $out .= substr( $base, $x[
'off'], $x[
'csize'] );
571 wfDebug( __METHOD__ .
": invalid op\n" );
586 if ( !function_exists(
'hash' ) ) {
591 if ( $init ===
null ) {
592 $init = str_repeat(
"\xf0", 205 ) .
"\xee" . str_repeat(
"\xf0", 67 ) .
"\x02";
598 return strrev( hash(
'adler32', $init .
$s,
true ) );
602 if ( !$this->mDiffs ) {
606 for ( $diffKey = 0; $diffKey < count( $this->mDiffs ); $diffKey++ ) {
607 $textKey = $this->mDiffMap[$diffKey];
608 $text = $this->
patch( $tail, $this->mDiffs[$diffKey] );
609 $this->mItems[$textKey] = $text;
619 if ( !count( $this->mItems ) ) {
626 foreach ( $this->mDiffMap
as $i ) {
634 'diffs' => $this->mDiffs,
638 if ( isset( $this->mDefaultKey ) ) {
641 $this->mCompressed = gzdeflate( serialize( $info ) );
642 return array(
'mCompressed' );
647 $this->mFrozen =
true;
648 $info = unserialize( gzinflate( $this->mCompressed ) );
649 unset( $this->mCompressed );
656 if ( isset( $info[
'default'] ) ) {
657 $this->mDefaultKey = $info[
'default'];
659 $this->mDiffs = $info[
'diffs'];
660 if ( isset( $info[
'base'] ) ) {
662 $this->mDiffMap = range( 0, count( $this->mDiffs ) - 1 );
663 array_unshift( $this->mDiffs,
664 pack(
'VVCV', 0, 0, self::XDL_BDOP_INSB, strlen( $info[
'base'] ) ) .
668 $map = explode(
',', $info[
'map'] );
670 $this->mDiffMap =
array();
671 foreach ( $map
as $i ) {
673 $this->mDiffMap[] = $cur;
686 return $this->mSize < $this->mMaxSize