function gmp_shiftr($x, $n)
{
    if ($x < 0) {
        return gmp_strval(gmp_com(gmp_div(gmp_com($x), gmp_pow(2, $n))));
    } else {
        return gmp_strval(gmp_div($x, gmp_pow(2, $n)));
    }
}
Example #2
0
/**
 * Calculate Wang hash for 64bit unsigned integer using GMP library
 * PHP only supports signed integers even with 64bit version
 *
 * See <code/nel/include/nel/misc/wang_hash.h> on https://bitbucket.org/ryzom/ryzomcore
 *
 * @param string $key
 *
 * @return string hash
 */
function wang_hash64($key)
{
    // force $key to be base 10
    $key = gmp_init($key, 10);
    //$key = (~$key) + ($key << 21);
    $key = gmp_add(gmp_com($key), gmp_mul($key, 1 << 21));
    //$key = $key ^ ($key >> 24);
    $key = gmp_xor($key, gmp_div($key, 1 << 24));
    //$key = $key * 265;
    $key = gmp_mul($key, 265);
    //$key = $key ^ ($key >> 14);
    $key = gmp_xor($key, gmp_div($key, 1 << 14));
    //$key = $key * 21;
    $key = gmp_mul($key, 21);
    //$key = $key ^ ($key >> 28);
    $key = gmp_xor($key, gmp_div($key, 1 << 28));
    //$key = $key + ($key << 31);
    $key = gmp_add($key, gmp_mul($key, gmp_pow(2, 31)));
    // limit to 64bit
    $key = gmp_and($key, "0xFFFFFFFFFFFFFFFF");
    return gmp_strval($key, 10);
}
Example #3
0
 /**
  * Scan the blobs table for rows not registered in blob_tracking (and thus not
  * registered in the text table).
  *
  * Orphan blobs are indicative of DB corruption. They are inaccessible and
  * should probably be deleted.
  */
 function findOrphanBlobs()
 {
     if (!extension_loaded('gmp')) {
         echo "Can't find orphan blobs, need bitfield support provided by GMP.\n";
         return;
     }
     $dbw = wfGetDB(DB_MASTER);
     foreach ($this->clusters as $cluster) {
         echo "Searching for orphan blobs in {$cluster}...\n";
         $lb = wfGetLBFactory()->getExternalLB($cluster);
         try {
             $extDB = $lb->getConnection(DB_SLAVE);
         } catch (DBConnectionError $e) {
             if (strpos($e->error, 'Unknown database') !== false) {
                 echo "No database on {$cluster}\n";
             } else {
                 echo "Error on {$cluster}: " . $e->getMessage() . "\n";
             }
             continue;
         }
         $table = $extDB->getLBInfo('blobs table');
         if (is_null($table)) {
             $table = 'blobs';
         }
         if (!$extDB->tableExists($table)) {
             echo "No blobs table on cluster {$cluster}\n";
             continue;
         }
         $startId = 0;
         $batchesDone = 0;
         $actualBlobs = gmp_init(0);
         $endId = $extDB->selectField($table, 'MAX(blob_id)', false, __METHOD__);
         // Build a bitmap of actual blob rows
         while (true) {
             $res = $extDB->select($table, array('blob_id'), array('blob_id > ' . $extDB->addQuotes($startId)), __METHOD__, array('LIMIT' => $this->batchSize, 'ORDER BY' => 'blob_id'));
             if (!$res->numRows()) {
                 break;
             }
             foreach ($res as $row) {
                 gmp_setbit($actualBlobs, $row->blob_id);
             }
             $startId = $row->blob_id;
             ++$batchesDone;
             if ($batchesDone >= $this->reportingInterval) {
                 $batchesDone = 0;
                 echo "{$startId} / {$endId}\n";
             }
         }
         // Find actual blobs that weren't tracked by the previous passes
         // This is a set-theoretic difference A \ B, or in bitwise terms, A & ~B
         $orphans = gmp_and($actualBlobs, gmp_com($this->trackedBlobs[$cluster]));
         // Traverse the orphan list
         $insertBatch = array();
         $id = 0;
         $numOrphans = 0;
         while (true) {
             $id = gmp_scan1($orphans, $id);
             if ($id == -1) {
                 break;
             }
             $insertBatch[] = array('bo_cluster' => $cluster, 'bo_blob_id' => $id);
             if (count($insertBatch) > $this->batchSize) {
                 $dbw->insert('blob_orphans', $insertBatch, __METHOD__);
                 $insertBatch = array();
             }
             ++$id;
             ++$numOrphans;
         }
         if ($insertBatch) {
             $dbw->insert('blob_orphans', $insertBatch, __METHOD__);
         }
         echo "Found {$numOrphans} orphan(s) in {$cluster}\n";
     }
 }
Example #4
0
 /**
  * @param $value
  * @param $mask
  *
  * @return string
  */
 public static function remove($value, $mask)
 {
     return gmp_strval(gmp_and($value, gmp_com($mask)));
 }
Example #5
0
echo gmp_strval($and1) . "\n";
echo gmp_strval($and2) . "\n";
// gmp_clrbit
$clrbit = gmp_init("0xff");
gmp_clrbit($clrbit, 0);
echo gmp_strval($clrbit) . "\n";
// gmp_cmp
$cmp1 = gmp_cmp("1234", "1000");
// greater than
$cmp2 = gmp_cmp("1000", "1234");
// less than
$cmp3 = gmp_cmp("1234", "1234");
// equal to
echo "{$cmp1} {$cmp2} {$cmp3}" . "\n";
// gmp_com
$com = gmp_com("1234");
echo gmp_strval($com) . "\n";
// gmp_div_q
$div1 = gmp_div_q("100", "5");
echo gmp_strval($div1) . "\n";
$div2 = gmp_div_q("1", "3");
echo gmp_strval($div2) . "\n";
$div3 = gmp_div_q("1", "3", GMP_ROUND_PLUSINF);
echo gmp_strval($div3) . "\n";
$div4 = gmp_div_q("-1", "4", GMP_ROUND_PLUSINF);
echo gmp_strval($div4) . "\n";
$div5 = gmp_div_q("-1", "4", GMP_ROUND_MINUSINF);
echo gmp_strval($div5) . "\n";
// gmp_div_qr
$a = gmp_init("0x41682179fbf5");
$res = gmp_div_qr($a, "0xDEFE75");
Example #6
0
 /**
  * Bitwise "not" (~)
  *
  * @access public
  * @return self
  */
 public function bitNot()
 {
     $result = gmp_com($this->getRawValue());
     return static::factory($result);
 }
Example #7
0
 /**
  * @param int $BitOffset
  * @param int $ValueMask
  * @param int $Value
  * 
  * @return void
  */
 private function Set($BitOffset, $ValueMask, $Value)
 {
     $this->Data = gmp_or(gmp_and($this->Data, gmp_com(self::ShiftLeft($ValueMask, $BitOffset))), self::ShiftLeft(gmp_and($Value, $ValueMask), $BitOffset));
 }
Example #8
0
 /**
  * @param BufferInterface $buffer
  * @return int
  */
 private function parseBuffer(BufferInterface $buffer)
 {
     $size = $buffer->getSize();
     if ($size === 0) {
         return '0';
     }
     $chars = array_map(function ($binary) {
         return ord($binary);
     }, str_split($buffer->getBinary(), 1));
     $result = 0;
     for ($i = 0; $i < $size; $i++) {
         $mul = $this->math->mul($i, 8);
         $byte = $this->math->leftShift($chars[$i], $mul);
         $result = $this->math->bitwiseOr($result, $byte);
     }
     if ($chars[count($chars) - 1] & 0x80) {
         $mask = gmp_strval(gmp_com($this->math->leftShift(0x80, 8 * ($size - 1))), 10);
         return $this->math->sub(0, $this->math->bitwiseAnd($result, $mask));
     }
     return $result;
 }
Example #9
0
 /**
  * Arithmetic right shift
  * @param resource|int|string $g
  * @param int $shift number of bits to shift right
  * @return resource $g shifted right $shift bits
  */
 static function shift_right($g, $shift)
 {
     if (0 == $shift) {
         return $g;
     }
     if (0 <= gmp_sign($g)) {
         $m = gmp_div($g, gmp_pow(self::gmp_2(), $shift));
     } else {
         $g = gmp_and($g, self::gmp_0xfs());
         $m = gmp_div($g, gmp_pow(self::gmp_2(), $shift));
         $m = gmp_and($m, self::gmp_0xfs());
         for ($i = 63; $i >= 63 - $shift; $i--) {
             gmp_setbit($m, $i);
         }
         $m = gmp_neg(gmp_add(gmp_and(gmp_com($m), self::gmp_0xfs()), self::gmp_1()));
     }
     return $m;
 }
 protected function readTextRecordInner(&$content, &$pos, $recordType)
 {
     switch ($recordType) {
         case Constants::RECORD_TYPE_ZERO_TEXT:
         case Constants::RECORD_TYPE_ZERO_TEXT_WITH_END_ELEMENT:
             return '0';
             break;
         case Constants::RECORD_TYPE_ONE_TEXT:
         case Constants::RECORD_TYPE_ONE_TEXT_WITH_END_ELEMENT:
             return '1';
             break;
         case Constants::RECORD_TYPE_FALSE_TEXT:
         case Constants::RECORD_TYPE_FALSE_TEXT_WITH_END_ELEMENT:
             return 'false';
             break;
         case Constants::RECORD_TYPE_TRUE_TEXT:
         case Constants::RECORD_TYPE_TRUE_TEXT_WITH_END_ELEMENT:
             return 'true';
             break;
         case Constants::RECORD_TYPE_INT8_TEXT:
         case Constants::RECORD_TYPE_INT8_TEXT_WITH_END_ELEMENT:
             $record = unpack('c*', $content[$pos]);
             $pos += 1;
             return (string) $record[1];
             break;
         case Constants::RECORD_TYPE_INT16_TEXT:
         case Constants::RECORD_TYPE_INT16_TEXT_WITH_END_ELEMENT:
             $record = unpack('s*', substr($content, $pos, 2));
             $pos += 2;
             return (string) $record[1];
             break;
         case Constants::RECORD_TYPE_INT32_TEXT:
         case Constants::RECORD_TYPE_INT32_TEXT_WITH_END_ELEMENT:
             $record = unpack('l*', substr($content, $pos, 4));
             $pos += 4;
             return (string) $record[1];
             break;
         case Constants::RECORD_TYPE_INT64_TEXT:
         case Constants::RECORD_TYPE_INT64_TEXT_WITH_END_ELEMENT:
             if (!function_exists('gmp_init')) {
                 throw new DecodingException('Int64 requires GMP extension');
             }
             list(, $int64Hex) = unpack('H*', strrev(substr($content, $pos, 8)));
             $pos += 8;
             return (string) gmp_strval(gmp_init($int64Hex, 16), 10);
             break;
         case Constants::RECORD_TYPE_FLOAT_TEXT:
         case Constants::RECORD_TYPE_FLOAT_TEXT_WITH_END_ELEMENT:
             $record = unpack('f*', substr($content, $pos, 4));
             $pos += 4;
             return (string) $record[1];
             break;
         case Constants::RECORD_TYPE_DOUBLE_TEXT:
         case Constants::RECORD_TYPE_DOUBLE_TEXT_WITH_END_ELEMENT:
             $record = unpack('d*', substr($content, $pos, 8));
             $pos += 8;
             return (string) $record[1];
             break;
         case Constants::RECORD_TYPE_DECIMAL_TEXT:
         case Constants::RECORD_TYPE_DECIMAL_TEXT_WITH_END_ELEMENT:
             if (!function_exists('gmp_init')) {
                 throw new DecodingException('Decimal requires GMP extension');
             }
             $pos += 2;
             // First 2 bytes reserved
             $scale = ord($content[$pos]);
             $pos += 1;
             $sign = ord($content[$pos]);
             $pos += 1;
             list(, $hi32Hex) = unpack('H*', strrev(substr($content, $pos, 4)));
             $pos += 4;
             $hi32 = gmp_init($hi32Hex, 16);
             list(, $lo64Hex) = unpack('H*', strrev(substr($content, $pos, 8)));
             $pos += 8;
             $lo64 = gmp_init($lo64Hex, 16);
             $value = gmp_add(gmp_mul($hi32, gmp_pow(2, 64)), $lo64);
             $record = gmp_strval($value, 10);
             if ($scale > 0) {
                 if ($scale > strlen($record)) {
                     $record = str_repeat('0', $scale - strlen($record)) . $record;
                 }
                 $record = substr($record, 0, strlen($record) - $scale) . '.' . substr($record, $scale * -1);
                 $record = trim($record, '0');
                 if ($record[0] == '.') {
                     $record = '0' . $record;
                 }
             }
             if ($sign == 0x80) {
                 $record = '-' . $record;
             }
             return $record;
             break;
         case Constants::RECORD_TYPE_DATETIME_TEXT:
         case Constants::RECORD_TYPE_DATETIME_TEXT_WITH_END_ELEMENT:
             if (!function_exists('gmp_init')) {
                 throw new DecodingException('Datetime requires GMP extension');
             }
             $binary = '';
             for ($i = 0; $i < 8; ++$i) {
                 list(, $byteint) = unpack('C*', $content[$pos + $i]);
                 $binary = sprintf('%08b', $byteint) . $binary;
             }
             $pos += 8;
             $value = gmp_init(substr($binary, 2, 62), 2);
             // Only calc with seconds, since PHP datetime doesn't support fractions
             $secsRemaining = gmp_div($value, '10000000');
             // Compensate for using unix timestamp
             $epochSecsRemaining = gmp_sub($secsRemaining, '62135596800');
             // Load PHP datetime with seconds remaining
             $datetime = new DateTime('@' . gmp_strval($epochSecsRemaining, 10), new DateTimeZone('UTC'));
             $date = $datetime->format('Y-m-d');
             $time = $datetime->format('H:i:s');
             // Get fractions
             $fraction = substr(gmp_strval($value, 10), -7);
             // Join different time elements
             if ($fraction !== '0000000') {
                 $record = "{$date}T{$time}.{$fraction}";
             } elseif ($time !== '00:00:00') {
                 $record = "{$date}T{$time}";
             } else {
                 $record = "{$date}";
             }
             // Add timezone info
             $tz = gmp_intval(gmp_init(substr($binary, 0, 2), 2));
             if ($tz == 2) {
                 // TODO: local time handling
             } elseif ($tz == 1) {
                 $record .= 'Z';
             }
             return $record;
             break;
         case Constants::RECORD_TYPE_CHARS8_TEXT:
         case Constants::RECORD_TYPE_CHARS8_TEXT_WITH_END_ELEMENT:
             list(, $recordLength) = unpack('C*', $content[$pos]);
             $pos += 1;
             $record = substr($content, $pos, $recordLength);
             $pos += $recordLength;
             return $record;
             break;
         case Constants::RECORD_TYPE_CHARS16_TEXT:
         case Constants::RECORD_TYPE_CHARS16_TEXT_WITH_END_ELEMENT:
             list(, $recordLength) = unpack('S*', substr($content, $pos, 2));
             $pos += 2;
             $record = substr($content, $pos, $recordLength);
             $pos += $recordLength;
             return $record;
             break;
         case Constants::RECORD_TYPE_CHARS32_TEXT:
         case Constants::RECORD_TYPE_CHARS32_TEXT_WITH_END_ELEMENT:
             list(, $recordLength) = unpack('l*', substr($content, $pos, 4));
             $pos += 4;
             $record = substr($content, $pos, $recordLength);
             $pos += $recordLength;
             return $record;
             break;
         case Constants::RECORD_TYPE_BYTES8_TEXT:
         case Constants::RECORD_TYPE_BYTES8_TEXT_WITH_END_ELEMENT:
             list(, $recordLength) = unpack('C*', $content[$pos]);
             $pos += 1;
             $record = substr($content, $pos, $recordLength);
             $pos += $recordLength;
             return base64_encode($record);
             break;
         case Constants::RECORD_TYPE_BYTES16_TEXT:
         case Constants::RECORD_TYPE_BYTES16_TEXT_WITH_END_ELEMENT:
             list(, $recordLength) = unpack('S*', substr($content, $pos, 2));
             $pos += 2;
             $record = substr($content, $pos, $recordLength);
             $pos += $recordLength;
             return base64_encode($record);
             break;
         case Constants::RECORD_TYPE_BYTES32_TEXT:
         case Constants::RECORD_TYPE_BYTES32_TEXT_WITH_END_ELEMENT:
             list(, $recordLength) = unpack('l*', substr($content, $pos, 4));
             $pos += 4;
             $record = substr($content, $pos, $recordLength);
             $pos += $recordLength;
             return base64_encode($record);
             break;
         case Constants::RECORD_TYPE_START_LIST_TEXT:
             $record = '';
             while (ord($content[$pos]) != Constants::RECORD_TYPE_END_LIST_TEXT) {
                 if ($record !== '') {
                     $record .= ' ';
                 }
                 $record .= $this->readTextRecord($content, $pos);
             }
             $pos += 1;
             // skip 1 for end list
             return $record;
             break;
         case Constants::RECORD_TYPE_EMPTY_TEXT:
         case Constants::RECORD_TYPE_EMPTY_TEXT_WITH_END_ELEMENT:
             return '';
             break;
         case Constants::RECORD_TYPE_DICTIONARY_TEXT:
         case Constants::RECORD_TYPE_DICTIONARY_TEXT_WITH_END_ELEMENT:
             return $this->readDictionaryString($content, $pos);
             break;
         case Constants::RECORD_TYPE_UNIQUEID_TEXT:
         case Constants::RECORD_TYPE_UNIQUEID_TEXT_WITH_END_ELEMENT:
         case Constants::RECORD_TYPE_UUID_TEXT:
         case Constants::RECORD_TYPE_UUID_TEXT_WITH_END_ELEMENT:
             list(, $data1) = unpack('H*', strrev(substr($content, $pos, 4)));
             $pos += 4;
             list(, $data2) = unpack('H*', strrev(substr($content, $pos, 2)));
             $pos += 2;
             list(, $data3) = unpack('H*', strrev(substr($content, $pos, 2)));
             $pos += 2;
             list(, $data4) = unpack('H*', substr($content, $pos, 2));
             $pos += 2;
             list(, $data5) = unpack('H*', substr($content, $pos, 6));
             $pos += 6;
             $record = "{$data1}-{$data2}-{$data3}-{$data4}-{$data5}";
             if ($recordType == Constants::RECORD_TYPE_UNIQUEID_TEXT || $recordType == Constants::RECORD_TYPE_UNIQUEID_TEXT_WITH_END_ELEMENT) {
                 $record = 'urn:uuid:' . $record;
             }
             return $record;
             break;
         case Constants::RECORD_TYPE_TIMESPAN_TEXT:
         case Constants::RECORD_TYPE_TIMESPAN_TEXT_WITH_END_ELEMENT:
             if (!function_exists('gmp_init')) {
                 throw new DecodingException('Timespan requires GMP extension');
             }
             $value = '';
             for ($i = 0; $i < 8; $i++) {
                 list(, $byte) = unpack('C*', $content[$pos + $i]);
                 $value = sprintf('%08b', $byte) . $value;
             }
             $pos += 8;
             $value = gmp_init($value, 2);
             $minus = false;
             if (gmp_testbit($value, 63)) {
                 $minus = true;
                 $mask = gmp_init(str_repeat('1', 64), '2');
                 $value = gmp_and(gmp_com($value), $mask);
                 $value = gmp_add($value, 1);
             }
             $remaining = gmp_abs($value);
             list($days, $remaining) = gmp_div_qr($remaining, gmp_init('864000000000'));
             list($hours, $remaining) = gmp_div_qr($remaining, gmp_init('36000000000'));
             list($mins, $remaining) = gmp_div_qr($remaining, gmp_init('600000000'));
             list($secs, $remaining) = gmp_div_qr($remaining, gmp_init('10000000'));
             $fracs = $remaining;
             $days = gmp_intval($days);
             $hours = gmp_intval($hours);
             $mins = gmp_intval($mins);
             $secs = gmp_intval($secs);
             $fracs = gmp_intval($fracs);
             $record = $minus ? '-P' : 'P';
             if ($days > 0) {
                 $record .= $days . 'D';
             }
             if ($hours > 0 || $mins > 0 || $secs > 0 || $fracs > 0) {
                 $record .= 'T';
                 if ($hours > 0) {
                     $record .= $hours . 'H';
                 }
                 if ($mins > 0) {
                     $record .= $mins . 'M';
                 }
                 if ($secs > 0 || $fracs > 0) {
                     $record .= $secs;
                     if ($fracs > 0) {
                         $record .= '.' . $fracs;
                     }
                     $record .= 'S';
                 }
             }
             return $record;
             break;
         case Constants::RECORD_TYPE_UINT64_TEXT:
         case Constants::RECORD_TYPE_UINT64_TEXT_WITH_END_ELEMENT:
             if (!function_exists('gmp_init')) {
                 throw new DecodingException('Uint64 requires GMP extension');
             }
             list(, $uint64Hex) = unpack('H*', strrev(substr($content, $pos, 8)));
             $pos += 8;
             return (string) gmp_strval(gmp_init($uint64Hex, 16), 10);
             break;
         case Constants::RECORD_TYPE_BOOL_TEXT:
         case Constants::RECORD_TYPE_BOOL_TEXT_WITH_END_ELEMENT:
             $record = ord($content[$pos]);
             $pos += 1;
             switch ($record) {
                 case 0:
                     return 'false';
                     break;
                 case 1:
                     return 'true';
                     break;
             }
             throw new DecodingException(sprintf('Unknown boolean value 0x%02X at position %d.', $record, $pos));
             break;
         case Constants::RECORD_TYPE_UNICODECHARS8_TEXT:
         case Constants::RECORD_TYPE_UNICODECHARS8_TEXT_WITH_END_ELEMENT:
             list(, $recordLength) = unpack('C*', $content[$pos]);
             $pos += 1;
             $record = substr($content, $pos, $recordLength);
             $pos += $recordLength;
             return mb_convert_encoding($record, 'UTF-8', 'UTF-16');
             break;
         case Constants::RECORD_TYPE_UNICODECHARS16_TEXT:
         case Constants::RECORD_TYPE_UNICODECHARS16_TEXT_WITH_END_ELEMENT:
             list(, $recordLength) = unpack('S*', substr($content, $pos, 2));
             $pos += 2;
             $record = substr($content, $pos, $recordLength);
             $pos += $recordLength;
             return mb_convert_encoding($record, 'UTF-8', 'UTF-16');
             break;
         case Constants::RECORD_TYPE_UNICODECHARS32_TEXT:
         case Constants::RECORD_TYPE_UNICODECHARS32_TEXT_WITH_END_ELEMENT:
             list(, $recordLength) = unpack('l*', substr($content, $pos, 4));
             $pos += 4;
             $record = substr($content, $pos, $recordLength);
             $pos += $recordLength;
             return mb_convert_encoding($record, 'UTF-8', 'UTF-16');
             break;
         case Constants::RECORD_TYPE_QNAMEDICTIONARY_TEXT:
         case Constants::RECORD_TYPE_QNAMEDICTIONARY_TEXT_WITH_END_ELEMENT:
             $prefix = chr(97 + ord($content[$pos]));
             $pos += 1;
             $name = $this->readDictionaryString($content, $pos);
             return $prefix . ':' . $name;
             break;
         default:
             throw new DecodingException(sprintf('Unknown record type 0x%02X at position %d.', $recordType, $pos));
             break;
     }
 }