Index: trunk/phase3/includes/HistoryBlob.php |
— | — | @@ -319,11 +319,13 @@ |
320 | 320 | * The maximum number of text items before the object becomes sad |
321 | 321 | */ |
322 | 322 | var $mMaxCount = 100; |
| 323 | + |
| 324 | + /** Constants from xdiff.h */ |
| 325 | + const XDL_BDOP_INS = 1; |
| 326 | + const XDL_BDOP_CPY = 2; |
| 327 | + const XDL_BDOP_INSB = 3; |
323 | 328 | |
324 | 329 | function __construct() { |
325 | | - if ( !function_exists( 'xdiff_string_bdiff' ) ){ |
326 | | - throw new MWException( "Need xdiff 1.5+ support to read or write DiffHistoryBlob\n" ); |
327 | | - } |
328 | 330 | if ( !function_exists( 'gzdeflate' ) ) { |
329 | 331 | throw new MWException( "Need zlib support to read or write DiffHistoryBlob\n" ); |
330 | 332 | } |
— | — | @@ -353,6 +355,9 @@ |
354 | 356 | } |
355 | 357 | |
356 | 358 | function compress() { |
| 359 | + if ( !function_exists( 'xdiff_string_bdiff' ) ){ |
| 360 | + throw new MWException( "Need xdiff 1.5+ support to write DiffHistoryBlob\n" ); |
| 361 | + } |
357 | 362 | if ( isset( $this->mDiffs ) ) { |
358 | 363 | // Already compressed |
359 | 364 | return; |
— | — | @@ -431,10 +436,60 @@ |
432 | 437 | } |
433 | 438 | |
434 | 439 | function patch( $base, $diff ) { |
435 | | - wfSuppressWarnings(); |
436 | | - $text = xdiff_string_bpatch( $base, $diff ) . ''; |
437 | | - wfRestoreWarnings(); |
438 | | - return $text; |
| 440 | + if ( function_exists( 'xdiff_string_bpatch' ) ) { |
| 441 | + wfSuppressWarnings(); |
| 442 | + $text = xdiff_string_bpatch( $base, $diff ) . ''; |
| 443 | + wfRestoreWarnings(); |
| 444 | + return $text; |
| 445 | + } |
| 446 | + |
| 447 | + # Pure PHP implementation |
| 448 | + |
| 449 | + $header = unpack( 'Vofp/Vcsize', substr( $diff, 0, 8 ) ); |
| 450 | + |
| 451 | + # Check the checksum if mhash is available |
| 452 | + if ( extension_loaded( 'mhash' ) ) { |
| 453 | + $ofp = mhash( MHASH_ADLER32, $base ); |
| 454 | + if ( $ofp !== substr( $diff, 0, 4 ) ) { |
| 455 | + wfDebug( __METHOD__. ": incorrect base checksum\n" ); |
| 456 | + return false; |
| 457 | + } |
| 458 | + } |
| 459 | + if ( $header['csize'] != strlen( $base ) ) { |
| 460 | + wfDebug( __METHOD__. ": incorrect base length {$header['csize']} -> {strlen($base)}\n" ); |
| 461 | + return false; |
| 462 | + } |
| 463 | + |
| 464 | + $p = 8; |
| 465 | + $out = ''; |
| 466 | + while ( $p < strlen( $diff ) ) { |
| 467 | + $x = unpack( 'Cop', substr( $diff, $p, 1 ) ); |
| 468 | + $op = $x['op']; |
| 469 | + ++$p; |
| 470 | + switch ( $op ) { |
| 471 | + case self::XDL_BDOP_INS: |
| 472 | + $x = unpack( 'Csize', substr( $diff, $p, 1 ) ); |
| 473 | + $p++; |
| 474 | + $out .= substr( $diff, $p, $x['size'] ); |
| 475 | + $p += $x['size']; |
| 476 | + break; |
| 477 | + case self::XDL_BDOP_INSB: |
| 478 | + $x = unpack( 'Vcsize', substr( $diff, $p, 4 ) ); |
| 479 | + $p += 4; |
| 480 | + $out .= substr( $diff, $p, $x['csize'] ); |
| 481 | + $p += $x['csize']; |
| 482 | + break; |
| 483 | + case self::XDL_BDOP_CPY: |
| 484 | + $x = unpack( 'Voff/Vcsize', substr( $diff, $p, 8 ) ); |
| 485 | + $p += 8; |
| 486 | + $out .= substr( $base, $x['off'], $x['csize'] ); |
| 487 | + break; |
| 488 | + default: |
| 489 | + wfDebug( __METHOD__.": invalid op\n" ); |
| 490 | + return false; |
| 491 | + } |
| 492 | + } |
| 493 | + return $out; |
439 | 494 | } |
440 | 495 | |
441 | 496 | function uncompress() { |