public void Test_Indexer() { var slice = new SliceWriter(); slice.WriteFixed64(0xBADC0FFEE0DDF00DUL); Assert.That(slice[0], Is.EqualTo(0x0D)); Assert.That(slice[1], Is.EqualTo(0xF0)); Assert.That(slice[2], Is.EqualTo(0xDD)); Assert.That(slice[3], Is.EqualTo(0xE0)); Assert.That(slice[4], Is.EqualTo(0xFE)); Assert.That(slice[5], Is.EqualTo(0x0F)); Assert.That(slice[6], Is.EqualTo(0xDC)); Assert.That(slice[7], Is.EqualTo(0xBA)); Assert.That(slice[-1], Is.EqualTo(0xBA)); Assert.That(slice[-2], Is.EqualTo(0xDC)); Assert.That(slice[-3], Is.EqualTo(0x0F)); Assert.That(slice[-4], Is.EqualTo(0xFE)); Assert.That(slice[-5], Is.EqualTo(0xE0)); Assert.That(slice[-6], Is.EqualTo(0xDD)); Assert.That(slice[-7], Is.EqualTo(0xF0)); Assert.That(slice[-8], Is.EqualTo(0x0D)); Assert.That(() => slice[8], Throws.InstanceOf <IndexOutOfRangeException>()); Assert.That(() => slice[-9], Throws.InstanceOf <IndexOutOfRangeException>()); }
/// <summary>Write the header to the file</summary> /// <param name="headerFlags"></param> /// <param name="uid"></param> /// <param name="sequence"></param> /// <param name="count"></param> /// <param name="timestamp"></param> /// <param name="attributes"></param> /// <remarks>This needs to be called before writing any level to the file</remarks> public Task WriteHeaderAsync(SnapshotFormat.Flags headerFlags, Uuid128 uid, ulong sequence, long count, long timestamp, IDictionary <string, IFdbTuple> attributes) { // The header will be use on ore more "pages", to simplify the job of loading / peeking at a stream content (no need for fancy buffering, just need to read 4K pages) // > The last page is padded with 0xAAs to detect corruption. m_uid = uid; m_sequence = sequence; m_itemCount = count; m_timestamp = timestamp; // HEADER // - DB_HEADER (64 bytes) // - DB ATTRIBUTES (variable size list of k/v) // - END_MARKER + HEADER_CRC // - PADDING (to fill last page) // DB Header // "PNDB" m_writer.WriteFixed32(SnapshotFormat.HEADER_MAGIC_NUMBER); // v1.0 m_writer.WriteFixed16(1); // major m_writer.WriteFixed16(0); // minor // FLAGS m_writer.WriteFixed64((ulong)headerFlags); // Database ID m_writer.WriteBytes(uid.ToSlice()); // Database Version m_writer.WriteFixed64(sequence); // Number of items in the database m_writer.WriteFixed64((ulong)count); // Database Timestamp m_writer.WriteFixed64((ulong)timestamp); // Page Size m_writer.WriteFixed32(SnapshotFormat.PAGE_SIZE); // Header Size (not known yet and will be filled in later) int offsetToHeaderSize = m_writer.Skip(4); // we should be at the 64 byte mark Contract.Assert(m_writer.Position == SnapshotFormat.HEADER_METADATA_BYTES); // DB Attributes m_writer.WriteFixed32((uint)attributes.Count); foreach (var kvp in attributes) { // Name m_writer.WriteVarbytes(Slice.FromString(kvp.Key)); // Value m_writer.WriteVarbytes(kvp.Value.ToSlice()); } // Mark the end of the header m_writer.WriteFixed32(uint.MaxValue); // we now have the size of the header, and can fill in the blank var headerEnd = m_writer.Position; m_writer.Position = offsetToHeaderSize; // write the header size (includes the CRC) m_writer.WriteFixed32((uint)checked (headerEnd + SnapshotFormat.HEADER_CRC_SIZE)); m_writer.Position = headerEnd; // now we can compute the actual CRC uint headerChecksum = SnapshotFormat.ComputeChecksum(m_writer.ToSlice()); m_writer.WriteFixed32(headerChecksum); m_headerChecksum = headerChecksum; // optional padding to fill the rest of the page PadPageIfNeeded(SnapshotFormat.PAGE_SIZE, 0xFD); return(TaskHelpers.CompletedTask); }