/// <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> /// 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; }