Example #1
0
 /**
  * @throws Exception
  */
 protected function finish()
 {
     // Hack for DBA cross-check
     $this->hplist = array_reverse($this->hplist);
     // Calculate the number of items that will be in each hashtable
     $counts = array_fill(0, 256, 0);
     foreach ($this->hplist as $item) {
         ++$counts[255 & $item['h']];
     }
     // Fill in $starts with the *end* indexes
     $starts = array();
     $pos = 0;
     for ($i = 0; $i < 256; ++$i) {
         $pos += $counts[$i];
         $starts[$i] = $pos;
     }
     // Excessively clever and indulgent code to simultaneously fill $packedTables
     // with the packed hashtables, and adjust the elements of $starts
     // to actually point to the starts instead of the ends.
     $packedTables = array_fill(0, $this->numentries, false);
     foreach ($this->hplist as $item) {
         $packedTables[--$starts[255 & $item['h']]] = $item;
     }
     $final = '';
     for ($i = 0; $i < 256; ++$i) {
         $count = $counts[$i];
         // The size of the hashtable will be double the item count.
         // The rest of the slots will be empty.
         $len = $count + $count;
         $final .= pack('VV', $this->pos, $len);
         $hashtable = array();
         for ($u = 0; $u < $len; ++$u) {
             $hashtable[$u] = array('h' => 0, 'p' => 0);
         }
         // Fill the hashtable, using the next empty slot if the hashed slot
         // is taken.
         for ($u = 0; $u < $count; ++$u) {
             $hp = $packedTables[$starts[$i] + $u];
             $where = Util::unsignedMod(Util::unsignedShiftRight($hp['h'], 8), $len);
             while ($hashtable[$where]['p']) {
                 if (++$where == $len) {
                     $where = 0;
                 }
             }
             $hashtable[$where] = $hp;
         }
         // Write the hashtable
         for ($u = 0; $u < $len; ++$u) {
             $buf = pack('vvV', $hashtable[$u]['h'] & 0xffff, Util::unsignedShiftRight($hashtable[$u]['h'], 16), $hashtable[$u]['p']);
             $this->write($buf);
             $this->posplus(8);
         }
     }
     // Write the pointer array at the start of the file
     rewind($this->handle);
     if (ftell($this->handle) != 0) {
         $this->throwException('Error rewinding to start of file "' . $this->tmpFileName . '".');
     }
     $this->write($final);
 }
Example #2
0
 /**
  * @param string $key
  * @return bool
  */
 protected function findNext($key)
 {
     if (!$this->loop) {
         $u = Util::hash($key);
         $buf = $this->read(8, $u << 3 & 2047);
         $this->hslots = $this->unpack31(substr($buf, 4));
         if (!$this->hslots) {
             return false;
         }
         $this->hpos = $this->unpack31(substr($buf, 0, 4));
         $this->khash = $u;
         $u = Util::unsignedShiftRight($u, 8);
         $u = Util::unsignedMod($u, $this->hslots);
         $u <<= 3;
         $this->kpos = $this->hpos + $u;
     }
     while ($this->loop < $this->hslots) {
         $buf = $this->read(8, $this->kpos);
         $pos = $this->unpack31(substr($buf, 4));
         if (!$pos) {
             return false;
         }
         $this->loop += 1;
         $this->kpos += 8;
         if ($this->kpos == $this->hpos + ($this->hslots << 3)) {
             $this->kpos = $this->hpos;
         }
         $u = $this->unpackSigned(substr($buf, 0, 4));
         if ($u === $this->khash) {
             $buf = $this->read(8, $pos);
             $keyLen = $this->unpack31(substr($buf, 0, 4));
             if ($keyLen == strlen($key) && $this->match($key, $pos + 8)) {
                 // Found
                 $this->dlen = $this->unpack31(substr($buf, 4));
                 $this->dpos = $pos + 8 + $keyLen;
                 return true;
             }
         }
     }
     return false;
 }
Example #3
0
 /**
  * Search the CDB file for a key.
  *
  * Sets `dataLen` and `dataPos` properties if successful.
  *
  * @param string $key
  * @return bool Whether the key was found.
  */
 protected function find($key)
 {
     $keyLen = strlen($key);
     $u = Util::hash($key);
     $upos = $u << 3 & 2047;
     $hashSlots = $this->readInt31($upos + 4);
     if (!$hashSlots) {
         return false;
     }
     $hashPos = $this->readInt31($upos);
     $keyHash = $u;
     $u = Util::unsignedShiftRight($u, 8);
     $u = Util::unsignedMod($u, $hashSlots);
     $u <<= 3;
     $keyPos = $hashPos + $u;
     for ($i = 0; $i < $hashSlots; $i++) {
         $hash = $this->readInt32($keyPos);
         $pos = $this->readInt31($keyPos + 4);
         if (!$pos) {
             return false;
         }
         $keyPos += 8;
         if ($keyPos == $hashPos + ($hashSlots << 3)) {
             $keyPos = $hashPos;
         }
         if ($hash === $keyHash) {
             if ($keyLen === $this->readInt31($pos)) {
                 $dataLen = $this->readInt31($pos + 4);
                 $dataPos = $pos + 8 + $keyLen;
                 $foundKey = $this->read($pos + 8, $keyLen);
                 if ($foundKey === $key) {
                     // Found
                     $this->dataLen = $dataLen;
                     $this->dataPos = $dataPos;
                     return true;
                 }
             }
         }
     }
     return false;
 }