private int _loop; // num of hash slots searched under current key /// <summary> /// Open a constant database from the given file. /// </summary> /// <param name="filePath">Path to the CDB file.</param> public CdbFile(string filePath) { _cdbFile = File.OpenRead(filePath); _heads = new UInt32[256 * 2]; var bytes = new byte[2048]; CdbRead(bytes, bytes.Length); for (int i = 0, offset = 0; i < 256; i++) { UInt32 pos = Cdb.UnpackInt32(bytes, offset); offset += 4; UInt32 len = Cdb.UnpackInt32(bytes, offset); offset += 4; _heads[i << 1] = pos; _heads[(i << 1) + 1] = len; } _loop = 0; }
/// <summary> /// Find the next record stored under the given <paramref name="key"/>. /// </summary> /// <returns>The next record stored under the given key, /// or <c>null</c> if no more records can be found.</returns> public byte[] FindNext(byte[] key) { // We change object state in here, so nobody must intervene! lock (_syncLock) { if (_cdbFile == null) { throw new ObjectDisposedException(GetType().Name); } // Initialize: locate hash table and entry in it: if (_loop == 0) { UInt32 u = Cdb.Hash(key); // Get hash table len&pos for this key: UInt32 slot = u & 255; _hslots = _heads[(slot << 1) + 1]; if (_hslots == 0) { return(null); } _hpos = _heads[slot << 1]; // Remember this key's hash: _khash = u; // Locate the slot in the table at _hpos: u >>= 8; u %= _hslots; u <<= 3; _kpos = _hpos + u; } // Search: iterate all hash slots for the given key: var bytes = new byte[8]; while (_loop < _hslots) { // Read the entry for this key from the hash slot CdbRead(bytes, 8, _kpos); UInt32 h = Cdb.UnpackInt32(bytes, 0); UInt32 pos = Cdb.UnpackInt32(bytes, 4); if (pos == 0) { break; } // Advance loop counter and key position. // Wrap key position if at end of hash table. _loop += 1; _kpos += 8; if (_kpos == (_hpos + (_hslots << 3))) { _kpos = _hpos; } // Different hash? Probe next slot... if (h != _khash) { continue; } // Jump to the record and see if key matches: CdbRead(bytes, 8, pos); UInt32 klen = Cdb.UnpackInt32(bytes, 0); if (klen != key.Length) { continue; } if (!CdbMatch(key)) { continue; } UInt32 dlen = Cdb.UnpackInt32(bytes, 4); // Keys match: fetch the data var data = new byte[dlen]; CdbRead(data, data.Length); return(data); } return(null); // No such key } }