/*- * See the file LICENSE for redistribution information. * * Copyright (c) 2009, 2015 Oracle and/or its affiliates. All rights reserved. * */ using System; using System.Collections; using System.Collections.Generic; using System.Text; using BerkeleyDB.Internal; namespace BerkeleyDB { /// /// A class providing access to multiple key/data pairs. /// public class MultipleKeyDatabaseEntry : DatabaseEntry, IEnumerable> { private bool _recno = false; internal MultipleKeyDatabaseEntry( DatabaseEntry dbt, bool recno) { _data = dbt.UserData; ulen = dbt.ulen; _recno = recno; } /// /// Construct a new bulk buffer for key/data pairs with a formatted /// byte array. /// /// The formatted byte array /// /// Whether the bulk is for recno/queue database. /// public MultipleKeyDatabaseEntry(byte[] data, bool recno) { UserData = data; _data = UserData; _recno = recno; flags |= DbConstants.DB_DBT_BULK; } /// /// Construct a new bulk buffer for key/data pairs. /// /// /// Whether the bulk buffer is for queue/recno database /// /// Enumerable key/data pairs public MultipleKeyDatabaseEntry( IEnumerable> data, bool recno) { List list = new List(); byte[] arr; int i; uint pos = 0; uint size; if (recno) { /* * For recno database, data value is written to the beginning * of the array, but the record number key is stored in the * "header" section, along with the offset and length of the * data value. Offset and length are not stored for the * recno key, since they are always 4 bytes. The list is * zero terminated (since -1 is a valid record number): * ------------------------------------------------------------- * |d1|..|dN|0|lengthN|offsetN|recnoN|..|length1|offset1|recno1| * ------------------------------------------------------------- */ List metadata = new List(); foreach (KeyValuePair pair in data) { size = pair.Value.size; arr = pair.Value.Data; for (i = 0; i < size; i++) list.Add(arr[i]); metadata.Add(pair.Key.Data); metadata.Add(BitConverter.GetBytes(pos)); metadata.Add(BitConverter.GetBytes(size)); pos += size; } for (i = 0; i < 4; i++) list.Add((byte)0); for (i = metadata.Count; i > 0; i--) { for (int j = 0; j < 4; j++) list.Add(metadata[i - 1][j]); } } else { /* * For non-recno database, the items are written to the * array in key/data pairs, but use the same layout as in * MultipleDatabaseEntry, with DBT.data values at the front * of the array, and header information at the end of the array. * -------------------------------------------------------- * |key1|data1|...|keyN|dataN|-1|lenDataN|offDataN| (linewrap) * -------------------------------------------------------- * |lenKeyN|offKeyN|...|lenData1|offData1||lenKey1|offKey1| * -------------------------------------------------------- */ List metadata = new List(); foreach (KeyValuePair pair in data) { size = pair.Key.size; arr = pair.Key.Data; metadata.Add(pos); metadata.Add(size); for (i = 0; i < (int)size; i++) list.Add(arr[i]); pos += size; size = pair.Value.size; arr = pair.Value.Data; metadata.Add(pos); metadata.Add(size); for (i = 0; i < (int)size; i++) list.Add(arr[i]); pos += size; } arr = BitConverter.GetBytes(-1); for (i = 0; i < 4; i++) list.Add(arr[i]); for (i = metadata.Count; i > 0; i--) { arr = BitConverter.GetBytes(metadata[i - 1]); for (int j = 0; j < 4; j++) list.Add(arr[j]); } } UserData = list.ToArray(); _data = UserData; _recno = recno; flags |= DbConstants.DB_DBT_BULK; } /// /// Whether the bulk buffer is for recno or queue database. /// public bool Recno { get { return _recno; } } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } /// /// Return an enumerator which iterates over all /// pairs represented by the /// . /// /// /// An enumerator for the /// public IEnumerator> GetEnumerator() { byte[] darr, karr; int off, sz; uint pos, recno; pos = ulen - 4; if (_recno) { recno = BitConverter.ToUInt32(_data, (int)pos); for (int i = 0; recno > 0; recno = BitConverter.ToUInt32(_data, (int)pos), i++) { pos -= 4; off = BitConverter.ToInt32(_data, (int)pos); pos -= 4; sz = BitConverter.ToInt32(_data, (int)pos); darr = new byte[sz]; Array.Copy(_data, off, darr, 0, sz); pos -= 4; yield return new KeyValuePair( new DatabaseEntry(BitConverter.GetBytes(recno)), new DatabaseEntry(darr)); } } else { off = BitConverter.ToInt32(_data, (int)pos); for (int i = 0; off >= 0; off = BitConverter.ToInt32(_data, (int)pos), i++) { pos -= 4; sz = BitConverter.ToInt32(_data, (int)pos); karr = new byte[sz]; Array.Copy(_data, off, karr, 0, sz); pos -= 4; off = BitConverter.ToInt32(_data, (int)pos); pos -= 4; sz = BitConverter.ToInt32(_data, (int)pos); darr = new byte[sz]; Array.Copy(_data, off, darr, 0, sz); pos -= 4; yield return new KeyValuePair( new DatabaseEntry(karr), new DatabaseEntry(darr)); } } } // public byte[][] Data; /* No Public Constructor */ //internal MultipleDatabaseEntry(DatabaseEntry dbt) { // byte[] dat = dbt.UserData; // List tmp = new List(); // uint pos = dbt.ulen - 4; // int off = BitConverter.ToInt32(dat, (int)pos); // for (int i = 0; off > 0; off = BitConverter.ToInt32(dat, (int)pos), i++) { // pos -= 4; // int sz = BitConverter.ToInt32(dat, (int)pos); // tmp.Add(new byte[sz]); // Array.Copy(dat, off, tmp[i], 0, sz); // pos -= 4; // } // Data = tmp.ToArray(); //} } }