//-------------------------------------------------
        public bool ReadBlock(Guid BlockID_in, ref Hashtable BlockTags_out, ref byte[] Bytes_out)
        {
            if ((this._Stream == null))
            {
                return(false);
            }
            if ((this._Blocks == null))
            {
                return(false);
            }
            int ndx = 0;

            if (!this.Internal_FindBlock(BlockID_in, ref ndx))
            {
                return(false);
            }
            StreamControlBlock BLK = (StreamControlBlock)this._Blocks[ndx];

            BlockTags_out = BlockStream.CloneObject <Hashtable>(BLK.Tags);
            try
            {
                this._Stream.Seek(this._Header.DataOffset + BLK.Offset, SeekOrigin.Begin);
                byte[] inbytes = new byte[BLK.Length];
                this._Stream.Read(inbytes, 0, inbytes.Length);
                if (!this._DecodeBytes(BlockTags_out, inbytes, ref Bytes_out))
                {
                    return(false);
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
            return(true);
        }
        //==========================================================================
        //===   Block Info
        //==========================================================================

        //-------------------------------------------------
        public long DataSize()
        {
            if ((this._Blocks.Count == 0))
            {
                return(0);
            }
            StreamControlBlock BLK = (StreamControlBlock)this._Blocks[this._Blocks.Count - 1];

            return(BLK.Offset + BLK.Length);
        }
        //-------------------------------------------------
        private bool Internal_AllocateBlock(Guid in_BlockID, int in_BlockLength, ref int out_BlockIndex)
        {
            //- - - - - - - - - - - - - - - - - - - - - - - - -
            out_BlockIndex = -1;
            if ((this._Blocks == null))
            {
                return(false);
            }
            StreamControlBlock BLK;
            StreamControlBlock BLK2;
            int ndx = 0;

            // Try to Reclaim an Existing Empty Block
            for (ndx = 0; ndx <= (this._Blocks.Count - 1); ndx++)
            {
                BLK = (StreamControlBlock)this._Blocks[ndx];
                if ((BLK.ID.CompareTo(Guid.Empty) == 0))
                {
                    if ((BLK.Length == in_BlockLength))
                    {
                        // Exact Size Match Found, just Reuse this Block
                        BLK.ID            = in_BlockID;
                        out_BlockIndex    = ndx;
                        this._BlocksDirty = true;
                        return(true);
                    }
                    else if ((BLK.Length > in_BlockLength))
                    {
                        // Larger Block Found, Split it into a Used Block and a Free Block
                        BLK2 = new StreamControlBlock(Guid.Empty);
                        this._Blocks.Insert(ndx + 1, BLK2);
                        BLK2.Offset       = (BLK.Offset + in_BlockLength);
                        BLK2.Length       = (BLK.Length - in_BlockLength);
                        BLK.ID            = in_BlockID;
                        BLK.Length        = in_BlockLength;
                        out_BlockIndex    = ndx;
                        this._BlocksDirty = true;
                        return(true);
                    }
                }
            }
            // Append a New Block
            BLK        = new StreamControlBlock(in_BlockID);
            BLK.Offset = 0;
            BLK.Length = in_BlockLength;
            ndx        = _Blocks.Add(BLK);
            if ((ndx > 0))
            {
                BLK2       = (StreamControlBlock)_Blocks[ndx - 1];
                BLK.Offset = (BLK2.Offset + BLK2.Length);
            }
            out_BlockIndex = ndx;
            _BlocksDirty   = true;
            return(true);
        }
        //-------------------------------------------------
        public bool WriteBlock(Guid BlockID_in, Hashtable BlockTags_in, byte[] Bytes_in)
        {
            if ((this._Stream == null))
            {
                return(false);
            }
            if (!this._Stream.CanWrite)
            {
                return(false);
            }
            if ((this._Blocks == null))
            {
                return(false);
            }
            int ndx = 0;

            if (this.Internal_FindBlock(BlockID_in, ref ndx))
            {
                // Free Existing Block
                if (!this.Internal_FreeBlock(ndx))
                {
                    return(false);
                }
            }
            // Encode Block
            byte[] outbytes = { };
            if (!this._EncodeBytes(BlockTags_in, Bytes_in, ref outbytes))
            {
                return(false);
            }
            // Allocate a New Block
            if (!this.Internal_AllocateBlock(BlockID_in, outbytes.Length, ref ndx))
            {
                return(false);
            }
            StreamControlBlock BLK = (StreamControlBlock)this._Blocks[ndx];

            try
            {
                this._Stream.Seek(this._Header.DataOffset + BLK.Offset, SeekOrigin.Begin);
                this._Stream.Write(outbytes, 0, outbytes.Length);
                BLK.Tags          = BlockStream.CloneObject <Hashtable>(BlockTags_in);
                this._BlocksDirty = true;
            }
            catch (Exception ex)
            {
                throw ex;
            }
            return(true);
        }