/// <summary>
        ///     Scan FAT o miniFAT for free sectors to reuse.
        /// </summary>
        /// <param name="sType">Type of sector to look for</param>
        /// <returns>A stack of available sectors or minisectors already allocated</returns>
        internal Queue<Sector> FindFreeSectors(SectorType sType)
        {
            var freeList = new Queue<Sector>();

            if (sType == SectorType.Normal)
            {
                var fatChain = GetSectorChain(-1, SectorType.FAT);
                var fatStream = new StreamView(fatChain, GetSectorSize(), _header.FATSectorsNumber*GetSectorSize(),
                    SourceStream);

                var idx = 0;

                while (idx < _sectors.Count)
                {
                    var id = fatStream.ReadInt32();

                    if (id == Sector.FreeSector)
                    {
                        if (_sectors[idx] == null)
                        {
                            var sector = new Sector(GetSectorSize(), SourceStream) {Id = idx};
                            _sectors[idx] = sector;
                        }

                        freeList.Enqueue(_sectors[idx]);
                    }

                    idx++;
                }
            }
            else
            {
                var miniFAT
                    = GetSectorChain(_header.FirstMiniFATSectorId, SectorType.Normal);

                var miniFATView
                    = new StreamView(miniFAT, GetSectorSize(), _header.MiniFATSectorsNumber*Sector.MinisectorSize,
                        SourceStream);

                var miniStream
                    = GetSectorChain(RootEntry.StartSector, SectorType.Normal);

                var miniStreamView
                    = new StreamView(miniStream, GetSectorSize(), RootStorage.Size, SourceStream);

                long ptr = 0;

                var nMinisectors = (int) (miniStreamView.Length/Sector.MinisectorSize);

                while (ptr < nMinisectors)
                {
                    //AssureLength(miniStreamView, (int)miniFATView.Length);

                    var id = miniFATView.ReadInt32();
                    ptr += 4;

                    if (id != Sector.FreeSector) continue;
                    var miniSector = new Sector(Sector.MinisectorSize, SourceStream)
                    {
                        Id = (int) ((ptr - 4)/4),
                        Type = SectorType.Mini
                    };

                    miniStreamView.Seek(miniSector.Id*Sector.MinisectorSize, SeekOrigin.Begin);
                    miniStreamView.Read(miniSector.GetData(), 0, Sector.MinisectorSize);

                    freeList.Enqueue(miniSector);
                }
            }

            return freeList;
        }
        /// <summary>
        ///     Setup the DIFAT sector chain
        /// </summary>
        /// <param name="faTsectorChain">A FAT sector chain</param>
        private void SetDIFATSectorChain(List<Sector> faTsectorChain)
        {
            // Get initial sector's count
            _header.FATSectorsNumber = faTsectorChain.Count;

            // Allocate Sectors
            foreach (var s in faTsectorChain)
            {
                if (s.Id != -1) continue;
                _sectors.Add(s);
                s.Id = _sectors.Count - 1;
                s.Type = SectorType.FAT;
            }

            // Sector count...
            var nCurrentSectors = _sectors.Count;

            // Temp DIFAT count
            var nDIFATSectors = (int) _header.DIFATSectorsNumber;

            if (faTsectorChain.Count > HeaderDIFATEntriesCount)
            {
                nDIFATSectors =
                    Ceiling((double) (faTsectorChain.Count - HeaderDIFATEntriesCount)/_difatSectorFATEntriesCount);
                nDIFATSectors = LowSaturation(nDIFATSectors - (int) _header.DIFATSectorsNumber); //required DIFAT
            }

            // ...sum with new required DIFAT sectors count
            nCurrentSectors += nDIFATSectors;

            // ReCheck FAT bias
            while (_header.FATSectorsNumber*_fatSectorEntriesCount < nCurrentSectors)
            {
                var extraFATSector = new Sector(GetSectorSize(), SourceStream);
                _sectors.Add(extraFATSector);

                extraFATSector.Id = _sectors.Count - 1;
                extraFATSector.Type = SectorType.FAT;

                faTsectorChain.Add(extraFATSector);

                _header.FATSectorsNumber++;
                nCurrentSectors++;

                //... so, adding a FAT sector may induce DIFAT sectors to increase by one
                // and consequently this may induce ANOTHER FAT sector (TO-THINK: May this condition occure ?)
                if (nDIFATSectors*_difatSectorFATEntriesCount >= (_header.FATSectorsNumber > HeaderDIFATEntriesCount
                    ? _header.FATSectorsNumber - HeaderDIFATEntriesCount
                    : 0)) continue;
                nDIFATSectors++;
                nCurrentSectors++;
            }

            var difatSectors = GetSectorChain(-1, SectorType.DIFAT);

            var difatStream = new StreamView(difatSectors, GetSectorSize(), SourceStream);

            // Write DIFAT Sectors (if required)
            // Save room for the following chaining
            for (var i = 0; i < faTsectorChain.Count; i++)
            {
                if (i < HeaderDIFATEntriesCount)
                    _header.DIFAT[i] = faTsectorChain[i].Id;
                else
                {
                    // room for DIFAT chaining at the end of any DIFAT sector (4 bytes)
                    if (i != HeaderDIFATEntriesCount &&
                        (i - HeaderDIFATEntriesCount)%_difatSectorFATEntriesCount == 0)
                    {
                        var temp = new byte[sizeof (int)];
                        difatStream.Write(temp, 0, sizeof (int));
                    }

                    difatStream.Write(BitConverter.GetBytes(faTsectorChain[i].Id), 0, sizeof (int));
                }
            }

            // Allocate room for DIFAT sectors
            foreach (var sector in difatStream.BaseSectorChain)
            {
                if (sector.Id != -1) continue;
                _sectors.Add(sector);
                sector.Id = _sectors.Count - 1;
                sector.Type = SectorType.DIFAT;
            }

            _header.DIFATSectorsNumber = (uint) nDIFATSectors;

            // Chain first sector
            if (difatStream.BaseSectorChain != null && difatStream.BaseSectorChain.Count > 0)
            {
                _header.FirstDIFATSectorId = difatStream.BaseSectorChain[0].Id;

                // Update header information
                _header.DIFATSectorsNumber = (uint) difatStream.BaseSectorChain.Count;

                // Write chaining information at the end of DIFAT Sectors
                for (var i = 0; i < difatStream.BaseSectorChain.Count - 1; i++)
                {
                    Buffer.BlockCopy(
                        BitConverter.GetBytes(difatStream.BaseSectorChain[i + 1].Id),
                        0,
                        difatStream.BaseSectorChain[i].GetData(),
                        GetSectorSize() - sizeof (int),
                        4);
                }

                Buffer.BlockCopy(
                    BitConverter.GetBytes(Sector.Endofchain),
                    0,
                    difatStream.BaseSectorChain[difatStream.BaseSectorChain.Count - 1].GetData(),
                    GetSectorSize() - sizeof (int),
                    sizeof (int)
                    );
            }
            else
                _header.FirstDIFATSectorId = Sector.Endofchain;

            // Mark DIFAT Sectors in FAT
            var fatSv = new StreamView(faTsectorChain, GetSectorSize(), _header.FATSectorsNumber*GetSectorSize(),
                SourceStream);

            for (var i = 0; i < _header.DIFATSectorsNumber; i++)
            {
                fatSv.Seek(difatStream.BaseSectorChain[i].Id*4, SeekOrigin.Begin);
                fatSv.Write(BitConverter.GetBytes(Sector.DifSector), 0, 4);
            }

            for (var i = 0; i < _header.FATSectorsNumber; i++)
            {
                fatSv.Seek(fatSv.BaseSectorChain[i].Id*4, SeekOrigin.Begin);
                fatSv.Write(BitConverter.GetBytes(Sector.FATSector), 0, 4);
            }

            _header.FATSectorsNumber = fatSv.BaseSectorChain.Count;
        }
        /// <summary>
        ///     Get a standard sector chain
        /// </summary>
        /// <param name="secId">First SecID of the required chain</param>
        /// <returns>A list of sectors</returns>
        /// <exception cref="CFCorruptedFileException">Raised when the file is corrupt</exception>
        private List<Sector> GetNormalSectorChain(int secId)
        {
            var result = new List<Sector>();

            var nextSecId = secId;

            var fatSectors = GetFatSectorChain();

            var fatStream
                = new StreamView(fatSectors, GetSectorSize(), fatSectors.Count*GetSectorSize(), SourceStream);

            while (true)
            {
                if (nextSecId == Sector.Endofchain) break;

                if (nextSecId >= _sectors.Count)
                    throw new CFCorruptedFileException(
                        string.Format(
                            "Next Sector ID reference an out of range sector. NextID : {0} while sector count {1}",
                            nextSecId, _sectors.Count));

                var sector = _sectors[nextSecId];
                if (sector == null)
                {
                    sector = new Sector(GetSectorSize(), SourceStream) {Id = nextSecId, Type = SectorType.Normal};
                    _sectors[nextSecId] = sector;
                }

                result.Add(sector);

                fatStream.Seek(nextSecId*4, SeekOrigin.Begin);
                var next = fatStream.ReadInt32();

                if (next != nextSecId)
                    nextSecId = next;
                else
                    throw new CFCorruptedFileException("Cyclic sector chain found. File is corrupted");
            }

            return result;
        }
        /// <summary>
        ///     Get a mini sector chain
        /// </summary>
        /// <param name="sectorId">First sector id of the required chain</param>
        /// <returns>A list of mini sectors (64 bytes)</returns>
        private List<Sector> GetMiniSectorChain(int sectorId)
        {
            var result = new List<Sector>();

            if (sectorId == Sector.Endofchain) return result;
            var miniFAT = GetNormalSectorChain(_header.FirstMiniFATSectorId);
            var miniStream = GetNormalSectorChain(RootEntry.StartSector);

            var miniFATView
                = new StreamView(miniFAT, GetSectorSize(), _header.MiniFATSectorsNumber*Sector.MinisectorSize,
                    SourceStream);

            var miniStreamView =
                new StreamView(miniStream, GetSectorSize(), RootStorage.Size, SourceStream);

            var miniFATReader = new BinaryReader(miniFATView);

            var nextSectorId = sectorId;

            while (true)
            {
                if (nextSectorId == Sector.Endofchain)
                    break;

                var miniSector = new Sector(Sector.MinisectorSize, SourceStream)
                {
                    Id = nextSectorId,
                    Type = SectorType.Mini
                };

                miniStreamView.Seek(nextSectorId*Sector.MinisectorSize, SeekOrigin.Begin);
                miniStreamView.Read(miniSector.GetData(), 0, Sector.MinisectorSize);

                result.Add(miniSector);

                miniFATView.Seek(nextSectorId*4, SeekOrigin.Begin);
                nextSectorId = miniFATReader.ReadInt32();
            }
            return result;
        }
        /// <summary>
        ///     Get the FAT sector chain
        /// </summary>
        /// <returns>List of FAT sectors</returns>
        private List<Sector> GetFatSectorChain()
        {
            const int numberOfHeaderFATEntry = 109; //Number of FAT sectors id in the header

            var result
                = new List<Sector>();

            int nextSecId;

            var difatSectors = GetDifatSectorChain();

            var idx = 0;

            // Read FAT entries from the header Fat entry array (max 109 entries)
            while (idx < _header.FATSectorsNumber && idx < numberOfHeaderFATEntry)
            {
                nextSecId = _header.DIFAT[idx];
                var sector = _sectors[nextSecId];

                if (sector == null)
                {
                    sector = new Sector(GetSectorSize(), SourceStream) {Id = nextSecId, Type = SectorType.FAT};
                    _sectors[nextSecId] = sector;
                }

                result.Add(sector);

                idx++;
            }

            //Is there any DIFAT sector containing other FAT entries ?
            if (difatSectors.Count <= 0) return result;
            var difatStream
                = new StreamView
                    (
                    difatSectors,
                    GetSectorSize(),
                    _header.FATSectorsNumber > numberOfHeaderFATEntry
                        ? (_header.FATSectorsNumber - numberOfHeaderFATEntry)*4
                        : 0,
                    SourceStream
                    );

            var nextDIFATSectorBuffer = new byte[4];

            difatStream.Read(nextDIFATSectorBuffer, 0, 4);
            nextSecId = BitConverter.ToInt32(nextDIFATSectorBuffer, 0);

            var i = 0;
            var numberOfFatHeaderEntries = numberOfHeaderFATEntry;

            while (numberOfFatHeaderEntries < _header.FATSectorsNumber)
            {
                if (difatStream.Position == ((GetSectorSize() - 4) + i*GetSectorSize()))
                {
                    difatStream.Seek(4, SeekOrigin.Current);
                    i++;
                    continue;
                }

                var sector = _sectors[nextSecId];

                if (sector == null)
                {
                    sector = new Sector(GetSectorSize(), SourceStream) {Type = SectorType.FAT, Id = nextSecId};
                    _sectors[nextSecId] = sector; //UUU
                }

                result.Add(sector);

                difatStream.Read(nextDIFATSectorBuffer, 0, 4);
                nextSecId = BitConverter.ToInt32(nextDIFATSectorBuffer, 0);
                numberOfFatHeaderEntries++;
            }

            return result;
        }
        /// <summary>
        ///     Get the DIFAT Sector chain
        /// </summary>
        /// <returns>A list of DIFAT sectors</returns>
        /// <exception cref="CFCorruptedFileException">Raised when DIFAT sectors count is mismatched</exception>
        private List<Sector> GetDifatSectorChain()
        {
            var result
                = new List<Sector>();

            if (_header.DIFATSectorsNumber == 0) return result;
            var validationCount = (int) _header.DIFATSectorsNumber;

            var sector = _sectors[_header.FirstDIFATSectorId];

            if (sector == null) //Lazy loading
            {
                sector = new Sector(GetSectorSize(), SourceStream)
                {
                    Type = SectorType.DIFAT,
                    Id = _header.FirstDIFATSectorId
                };
                _sectors[_header.FirstDIFATSectorId] = sector;
            }

            result.Add(sector);

            while (validationCount >= 0)
            {
                var nextSecId = BitConverter.ToInt32(sector.GetData(), GetSectorSize() - 4);

                // Strictly speaking, the following condition is not correct from
                // a specification point of view:
                // only ENDOFCHAIN should break DIFAT chain but
                // a lot of existing compound files use FREESECT as DIFAT chain termination
                if (nextSecId == Sector.FreeSector || nextSecId == Sector.Endofchain) break;

                validationCount--;

                if (validationCount < 0)
                {
                    Close();
                    throw new CFCorruptedFileException("DIFAT sectors count mismatched. Corrupted compound file");
                }

                sector = _sectors[nextSecId];

                if (sector == null)
                {
                    sector = new Sector(GetSectorSize(), SourceStream) {Id = nextSecId};
                    _sectors[nextSecId] = sector;
                }

                result.Add(sector);
            }

            return result;
        }