Example #1
0
        /// <summary>
        /// Adds a key to the constant database.
        /// </summary>
        /// <param name="key">The key to add to the database.</param>
        /// <param name="data">The data associated with this key.</param>
        /// <exception cref="System.IO.IOException">If an error occurs adding the key
        ///  to the database.</exception>
        public void Add(byte[] key, byte[] data)
        {
            /* Write out the key length. */
            CdbUtils.WriteLittleEndianInt32(fileStream, key.Length);

            /* Write out the data length. */
            CdbUtils.WriteLittleEndianInt32(fileStream, data.Length);

            /* Write out the key. */
            fileStream.Write(key, 0, key.Length);

            /* Write out the data. */
            fileStream.Write(data, 0, data.Length);


            /* Add the hash pointer to our list. */
            int hash = CdbUtils.Hash(key);

            hashPointers.Add(new CdbHashPointer(hash, currentKeyPos));

            /* Add this item to the count. */
            tableCount[hash & 0xff]++;


            /* Update the file position pointer. */
            PosPlus(8);
            PosPlus(key.Length);
            PosPlus(data.Length);
        }
        /* Returns the next data element in the CDB file. */
        private CdbEntry NextElement()
        {
            try
            {
                /* Read the key and value lengths. */
                int klen = CdbUtils.ReadLittleEndianInt32(cdbStream);
                pos += 4;
                int dlen = CdbUtils.ReadLittleEndianInt32(cdbStream);
                pos += 4;

                /* Read the key. */
                byte[] key = new byte[klen];
                for (int off = 0; off < klen;)  // below
                {
                    int count = cdbStream.Read(key, off, klen - off);
                    if (count == -1)
                    {
                        throw new ArgumentException("invalid cdb format");
                    }
                    off += count;
                }
                pos += klen;

                /* Read the data. */
                byte[] data = new byte[dlen];
                for (int off = 0; off < dlen;)  // below
                {
                    int count = cdbStream.Read(data, off, dlen - off);
                    if (count == -1)
                    {
                        throw new ArgumentException("invalid cdb format");
                    }
                    off += count;
                }
                pos += dlen;

                /* Return a CdbElement with the key and data. */
                return(new CdbEntry(key, data));
            }
            catch (IOException)
            {
                throw new ArgumentException("invalid cdb format");
            }
        }
Example #3
0
        /// <summary>
        /// Finds the next record stored under the given key.
        /// </summary>
        /// <param name="key"> The key to search for. </param>
        /// <returns> The next record store under the given key, or
        ///  <code>null</code> if no record with that key could be found. </returns>
        public byte[] FindNext(byte[] key)
        {
            lock (this)
            {
                /* There are no keys if we could not read the slot table. */
                if (slotTable == null)
                {
                    return(null);
                }

                /* Locate the hash entry if we have not yet done so. */
                if (numberOfHashSlotsSearched == 0)
                {
                    /* Get the hash value for the key. */
                    int u = CdbUtils.Hash(key);

                    /* Unpack the information for this record. */
                    int slot = u & 255;
                    numberOfHashSlots = slotTable[(slot << 1) + 1];
                    if (numberOfHashSlots == 0)
                    {
                        return(null);
                    }
                    currentKeyHashTablePos = slotTable[slot << 1];

                    /* Store the hash value. */
                    currentKeyHashValue = u;

                    /* Locate the slot containing this key. */
                    u             = (int)((uint)u >> 8);
                    u            %= numberOfHashSlots;
                    u           <<= 3;
                    currentKeyPos = currentKeyHashTablePos + u;
                }

                /* Search all of the hash slots for this key. */
                try
                {
                    while (numberOfHashSlotsSearched < numberOfHashSlots)
                    {
                        /* Read the entry for this key from the hash slot. */
                        fileStream.Seek(currentKeyPos, SeekOrigin.Begin);

                        int h = fileStream.ReadByte() | (fileStream.ReadByte() << 8) | (fileStream.ReadByte() << 16) |
                                (fileStream.ReadByte() << 24);

                        int pos = fileStream.ReadByte() | (fileStream.ReadByte() << 8) | (fileStream.ReadByte() << 16) |
                                  (fileStream.ReadByte() << 24);
                        if (pos == 0)
                        {
                            return(null);
                        }

                        /* Advance the loop count and key position.  Wrap the
                         * key position around to the beginning of the hash slot
                         * if we are at the end of the table. */
                        numberOfHashSlotsSearched += 1;

                        currentKeyPos += 8;
                        if (currentKeyPos == (currentKeyHashTablePos + (numberOfHashSlots << 3)))
                        {
                            currentKeyPos = currentKeyHashTablePos;
                        }

                        /* Ignore this entry if the hash values do not match. */
                        if (h != currentKeyHashValue)
                        {
                            continue;
                        }

                        /* Get the length of the key and data in this hash slot
                         * entry. */
                        fileStream.Seek(pos, SeekOrigin.Begin);

                        int klen = fileStream.ReadByte() | (fileStream.ReadByte() << 8) | (fileStream.ReadByte() << 16) |
                                   (fileStream.ReadByte() << 24);
                        if (klen != key.Length)
                        {
                            continue;
                        }

                        int dlen = fileStream.ReadByte() | (fileStream.ReadByte() << 8) | (fileStream.ReadByte() << 16) |
                                   (fileStream.ReadByte() << 24);

                        /* Read the key stored in this entry and compare it to
                         * the key we were given. */
                        bool   match = true;
                        byte[] k     = new byte[klen];
                        fileStream.Read(k, 0, k.Length);
                        for (int i = 0; i < k.Length; i++)
                        {
                            if (k[i] != key[i])
                            {
                                match = false;
                                break;
                            }
                        }

                        /* No match; check the next slot. */
                        if (!match)
                        {
                            continue;
                        }

                        /* The keys match, return the data. */
                        byte[] d = new byte[dlen];
                        fileStream.Read(d, 0, d.Length);
                        return(d);
                    }
                }
                catch (IOException)
                {
                    return(null);
                }

                /* No more data values for this key. */
                return(null);
            }
        }
Example #4
0
        /// <summary>
        /// Finalizes the constant database.
        /// </summary>
        /// <exception cref="System.IO.IOException">If an error occurs closing out the
        ///  database.</exception>
        public void Finish()
        {
            if (fileStream == null)
            {
                return;
            }

            /* Find the start of each hash table. */
            int curEntry = 0;

            for (int i = 0; i < 256; i++)
            {
                curEntry     += tableCount[i];
                tableStart[i] = curEntry;
            }

            /* Create a new hash pointer list in order by hash table. */
            CdbHashPointer[] slotPointers = new CdbHashPointer[hashPointers.Count];
            foreach (CdbHashPointer hp in hashPointers)
            {
                slotPointers[--tableStart[hp.HashValue & 0xff]] = hp;
            }

            /* Write out each of the hash tables, building the slot table in
             * the process. */
            byte[] slotTable = new byte[2048];
            for (int i = 0; i < 256; i++)
            {
                /* Get the length of the hashtable. */
                int len = tableCount[i] * 2;

                /* Store the position of this table in the slot table. */
                slotTable[(i * 8) + 0]     = unchecked ((byte)(currentKeyPos & 0xff));
                slotTable[(i * 8) + 1]     = unchecked ((byte)(((int)((uint)currentKeyPos >> 8)) & 0xff));
                slotTable[(i * 8) + 2]     = unchecked ((byte)(((int)((uint)currentKeyPos >> 16)) & 0xff));
                slotTable[(i * 8) + 3]     = unchecked ((byte)(((int)((uint)currentKeyPos >> 24)) & 0xff));
                slotTable[(i * 8) + 4 + 0] = unchecked ((byte)(len & 0xff));
                slotTable[(i * 8) + 4 + 1] = unchecked ((byte)(((int)((uint)len >> 8)) & 0xff));
                slotTable[(i * 8) + 4 + 2] = unchecked ((byte)(((int)((uint)len >> 16)) & 0xff));
                slotTable[(i * 8) + 4 + 3] = unchecked ((byte)(((int)((uint)len >> 24)) & 0xff));

                /* Build the hash table. */
                int curSlotPointer         = tableStart[i];
                CdbHashPointer[] hashTable = new CdbHashPointer[len];
                for (int u = 0; u < tableCount[i]; u++)
                {
                    /* Get the hash pointer. */
                    CdbHashPointer hp = slotPointers[curSlotPointer++];

                    /* Locate a free space in the hash table. */
                    int @where = ((int)((uint)hp.HashValue >> 8)) % len;
                    while (hashTable[@where] != null)
                    {
                        if (++@where == len)
                        {
                            @where = 0;
                        }
                    }

                    /* Store the hash pointer. */
                    hashTable[@where] = hp;
                }

                /* Write out the hash table. */
                for (int u = 0; u < len; u++)
                {
                    CdbHashPointer hp = hashTable[u];
                    if (hp != null)
                    {
                        CdbUtils.WriteLittleEndianInt32(fileStream, hashTable[u].HashValue);
                        CdbUtils.WriteLittleEndianInt32(fileStream, hashTable[u].EntryPos);
                    }
                    else
                    {
                        CdbUtils.WriteLittleEndianInt32(fileStream, 0);
                        CdbUtils.WriteLittleEndianInt32(fileStream, 0);
                    }
                    PosPlus(8);
                }
            }

            /* Seek back to the beginning of the file and write out the
             * slot table. */
            fileStream.Seek(0, SeekOrigin.Begin);
            fileStream.Write(slotTable, 0, slotTable.Length);

            /* Close the file. */
            fileStream.Dispose();
            fileStream = null;
        }