41 if ( $a & 0x80000000 ) {
42 $m = ( $a & 0x7fffffff ) % $b + 2 * ( 0x40000000 % $b );
60 if ( $a & 0x80000000 ) {
61 return ( ( $a & 0x7fffffff ) >> $b ) | ( 0x40000000 >> ( $b - 1 ) );
77 for ( $i = 0; $i < $len; $i++ ) {
78 $h5 = ( $h << 5 ) & 0xffffffff;
81 $sum = ( $h & 0x3fffffff ) + ( $h5 & 0x3fffffff );
84 ( $sum & 0x40000000 ? 1 : 0 )
85 + ( $h & 0x80000000 ? 2 : 0 )
86 + ( $h & 0x40000000 ? 1 : 0 )
87 + ( $h5 & 0x80000000 ? 2 : 0 )
88 + ( $h5 & 0x40000000 ? 1 : 0 )
90 | ( $sum & 0x3fffffff );
133 $this->handle = fopen(
$fileName,
'rb' );
134 if ( !$this->handle ) {
135 throw new CdbException(
'Unable to open CDB file "' . $this->fileName .
'".' );
141 if ( isset( $this->handle ) ) {
142 fclose( $this->handle );
144 unset( $this->handle );
151 public function get( $key ) {
153 if ( $this->
find( strval( $key ) ) ) {
154 return $this->
read( $this->dlen, $this->dpos );
165 protected function match( $key, $pos ) {
166 $buf = $this->
read( strlen( $key ), $pos );
168 return $buf === $key;
181 protected function read( $length, $pos ) {
182 if ( fseek( $this->handle, $pos ) == -1 ) {
185 'Seek failed, file "' . $this->fileName .
'" may be corrupted.' );
188 if ( $length == 0 ) {
192 $buf = fread( $this->handle, $length );
193 if ( $buf ===
false || strlen( $buf ) !== $length ) {
195 'Read from CDB file failed, file "' . $this->fileName .
'" may be corrupted.' );
208 $data = unpack(
'V',
$s );
209 if ( $data[1] > 0x7fffffff ) {
211 'Error in CDB file "' . $this->fileName .
'", integer too big.' );
223 $data = unpack(
'va/vb',
$s );
225 return $data[
'a'] | ( $data[
'b'] << 16 );
233 if ( !$this->loop ) {
235 $buf = $this->
read( 8, ( $u << 3 ) & 2047 );
236 $this->hslots = $this->
unpack31( substr( $buf, 4 ) );
237 if ( !$this->hslots ) {
240 $this->hpos = $this->
unpack31( substr( $buf, 0, 4 ) );
245 $this->kpos = $this->hpos + $u;
248 while ( $this->loop < $this->hslots ) {
249 $buf = $this->
read( 8, $this->kpos );
250 $pos = $this->
unpack31( substr( $buf, 4 ) );
256 if ( $this->kpos == $this->hpos + ( $this->hslots << 3 ) ) {
260 if ( $u === $this->khash ) {
261 $buf = $this->
read( 8, $pos );
262 $keyLen = $this->
unpack31( substr( $buf, 0, 4 ) );
263 if ( $keyLen == strlen( $key ) && $this->
match( $key, $pos + 8 ) ) {
265 $this->dlen = $this->
unpack31( substr( $buf, 4 ) );
266 $this->dpos = $pos + 8 + $keyLen;
280 protected function find( $key ) {
298 $this->realFileName = $fileName;
299 $this->tmpFileName = $fileName .
'.tmp.' . mt_rand( 0, 0x7fffffff );
300 $this->handle = fopen( $this->tmpFileName,
'wb' );
301 if ( !$this->handle ) {
303 'Unable to open CDB file "' . $this->tmpFileName .
'" for write.' );
305 $this->hplist =
array();
306 $this->numentries = 0;
308 if ( fseek( $this->handle, $this->pos ) == -1 ) {
309 $this->
throwException(
'fseek failed in file "' . $this->tmpFileName .
'".' );
318 if ( strval( $key ) ===
'' ) {
323 $this->
write( $key );
333 if ( isset( $this->handle ) ) {
334 fclose( $this->handle );
336 if ( $this->
isWindows() && file_exists( $this->realFileName ) ) {
337 unlink( $this->realFileName );
339 if ( !rename( $this->tmpFileName, $this->realFileName ) ) {
340 $this->
throwException(
'Unable to move the new CDB file into place.' );
342 unset( $this->handle );
350 $len = fwrite( $this->handle, $buf );
351 if ( $len !== strlen( $buf ) ) {
352 $this->
throwException(
'Error writing to CDB file "' . $this->tmpFileName .
'".' );
361 $newpos = $this->pos + $len;
362 if ( $newpos > 0x7fffffff ) {
364 'A value in the CDB file "' . $this->tmpFileName .
'" is too large.' );
366 $this->pos = $newpos;
374 protected function addend( $keylen, $datalen, $h ) {
375 $this->hplist[] =
array(
392 if ( $keylen > 0x7fffffff ) {
393 $this->
throwException(
'Key length too long in file "' . $this->tmpFileName .
'".' );
395 if ( $datalen > 0x7fffffff ) {
396 $this->
throwException(
'Data length too long in file "' . $this->tmpFileName .
'".' );
398 $buf = pack(
'VV', $keylen, $datalen );
399 $this->
write( $buf );
407 $this->hplist = array_reverse( $this->hplist );
410 $counts = array_fill( 0, 256, 0 );
411 foreach ( $this->hplist
as $item ) {
412 ++$counts[255 & $item[
'h']];
418 for ( $i = 0; $i < 256; ++$i ) {
426 $packedTables = array_fill( 0, $this->numentries,
false );
427 foreach ( $this->hplist
as $item ) {
428 $packedTables[--$starts[255 & $item[
'h']]] = $item;
432 for ( $i = 0; $i < 256; ++$i ) {
438 $final .= pack(
'VV', $this->pos, $len );
440 $hashtable =
array();
441 for ( $u = 0; $u < $len; ++$u ) {
442 $hashtable[$u] =
array(
'h' => 0,
'p' => 0 );
447 for ( $u = 0; $u <
$count; ++$u ) {
448 $hp = $packedTables[$starts[$i] + $u];
451 while ( $hashtable[$where][
'p'] ) {
452 if ( ++$where == $len ) {
456 $hashtable[$where] = $hp;
460 for ( $u = 0; $u < $len; ++$u ) {
462 $hashtable[$u][
'h'] & 0xffff,
464 $hashtable[$u][
'p'] );
465 $this->
write( $buf );
471 rewind( $this->handle );
472 if ( ftell( $this->handle ) != 0 ) {
473 $this->
throwException(
'Error rewinding to start of file "' . $this->tmpFileName .
'".' );
475 $this->
write( $final );
485 if ( $this->handle ) {
486 fclose( $this->handle );
487 unlink( $this->tmpFileName );