/// <summary> /// Read the next entry. /// </summary> /// <returns>The read DBEntry if any; null otherwise.</returns> public DBEntry Read() { switch (state) { case ReaderState.EndOfFile: { return(null); } case ReaderState.ReadHeaderNext: { LastReadEntry = Header = DBHeader.ReadFrom(binaryReader, strBuilder); state = ReaderState.ReadRootDirectoryNext; return(LastReadEntry); } case ReaderState.ReadRootDirectoryNext: { positionBeforeReadRootDirectory = inputStream.Position; LastReadEntry = currentRootDirectory = DBRootDirectoryEntry.ReadFrom(binaryReader, strBuilder); if (currentRootDirectory == null) { state = ReaderState.EndOfFile; return(null); } currentPathStack.Push(currentPath = currentRootDirectory.Path); currentRootDirectory.FullName = currentPath; state = ReaderState.ReadFileOrDirectoryNext; return(LastReadEntry); } case ReaderState.ReadFileOrDirectoryNext: { typeAndAttributes = (DBEntryAttributes)binaryReader.ReadByte(); if (typeAndAttributes != 0 || depth > 0) { if (typeAndAttributes.HasFlag(DBEntryAttributes.Directory)) { positionBeforeReadDirectory = inputStream.Position; var directoryEntry = DBDirectoryEntry.ReadFrom(binaryReader, typeAndAttributes, strBuilder); currentPath += (depth == 0 ? string.Empty : @"\") + directoryEntry.DirectoryName; directoryEntry.ParentDirectory = depth == 0 ? null : dirStack.Peek(); directoryEntry.RootDirectory = currentRootDirectory; directoryEntry.FullName = currentPath; depth++; dirStack.Push(directoryEntry); return(LastReadEntry = directoryEntry); } if (typeAndAttributes != 0) { var fileEntry = DBFileEntry.ReadFrom(binaryReader, typeAndAttributes, strBuilder); fileEntry.ParentDirectory = depth == 0 ? null : dirStack.Peek(); fileEntry.RootDirectory = currentRootDirectory; fileEntry.FullName = currentPath + (depth == 0 ? string.Empty : @"\") + fileEntry.FileName; return(LastReadEntry = fileEntry); } depth--; var poppedDir = dirStack.Pop(); currentPath = poppedDir.ParentDirectory?.FullName ?? poppedDir.RootDirectory?.FullName ?? string.Empty; return(Read()); } var nullByte = binaryReader.ReadByte(); // normally its a dword byte but we should already have read a zero byte before if (nullByte != 0) { throw new ArchiveException($"Was expecting to read a final null-byte, read {nullByte} instead."); } currentPathStack.Pop(); state = ReaderState.ReadRootDirectoryNext; return(Read()); } } LastReadEntry = null; return(null); }
public IEnumerable <DBEntry> EnumerateEntries(IDBEntryFilter filter) { var strBuilder = new StringBuilder(255); var header = DBHeader.ReadFrom(binaryReader, strBuilder); var hasFilter = filter != null; // Always return the header as the first entry yield return(header); // var positionBeforeRead = inputStream.Position; var positionBeforeReadRootDirectory = inputStream.Position; var currentRootDirectory = DBRootDirectoryEntry.ReadFrom(binaryReader, strBuilder); // var readLength = inputStream.Position - positionBeforeRead; int depth = 0; var dirs = new Stack <DBDirectoryEntry>(); var currentPathStack = new Stack <string>(64); while (currentRootDirectory != null) { string currentPath; currentPathStack.Push(currentPath = currentRootDirectory.Path); currentRootDirectory.FullName = currentPath; var filterResult = filter?.Filter(currentRootDirectory) ?? DBEntryFilterResultActions.ExcludeNothing; if (!hasFilter || (filterResult == DBEntryFilterResultActions.ExcludeNothing || !filterResult.HasFlag(DBEntryFilterResultActions.ExcludeSelf))) { yield return(currentRootDirectory); } if (hasFilter && filterResult.HasFlag(DBEntryFilterResultActions.ExcludeChildren)) { // Skip the rest inputStream.Position += (positionBeforeReadRootDirectory - inputStream.Position) + currentRootDirectory.DataLength + 4; currentPathStack.Pop(); positionBeforeReadRootDirectory = inputStream.Position; currentRootDirectory = DBRootDirectoryEntry.ReadFrom(binaryReader, strBuilder); continue; } var typeAndAttributes = (DBEntryAttributes)binaryReader.ReadByte(); while (typeAndAttributes != 0 || depth > 0) { if (typeAndAttributes.HasFlag(DBEntryAttributes.Directory)) { var positionBeforeReadDirectory = inputStream.Position; var directoryEntry = DBDirectoryEntry.ReadFrom(binaryReader, typeAndAttributes, strBuilder); currentPath += (depth == 0 ? string.Empty : @"\") + directoryEntry.DirectoryName; directoryEntry.ParentDirectory = depth == 0 ? null : dirs.Peek(); directoryEntry.RootDirectory = currentRootDirectory; directoryEntry.FullName = currentPath; filterResult = filter?.Filter(directoryEntry) ?? DBEntryFilterResultActions.ExcludeNothing; if (!hasFilter || (filterResult == DBEntryFilterResultActions.ExcludeNothing || !filterResult.HasFlag(DBEntryFilterResultActions.ExcludeSelf))) { yield return(directoryEntry); } if (hasFilter && filterResult.HasFlag(DBEntryFilterResultActions.ExcludeChildren)) { // Skip the rest inputStream.Position += (positionBeforeReadDirectory - inputStream.Position) + directoryEntry.DataLength; var poppedDir = dirs.Count > 0 ? dirs.Peek() : null; currentPath = poppedDir?.ParentDirectory?.FullName ?? directoryEntry?.RootDirectory?.FullName ?? string.Empty; } else { depth++; dirs.Push(directoryEntry); } } else if (typeAndAttributes != 0) { var fileEntry = DBFileEntry.ReadFrom(binaryReader, typeAndAttributes, strBuilder); fileEntry.ParentDirectory = depth == 0 ? null : dirs.Peek(); fileEntry.RootDirectory = currentRootDirectory; fileEntry.FullName = currentPath + (depth == 0 ? string.Empty : @"\") + fileEntry.FileName; if (!hasFilter || (filterResult == DBEntryFilterResultActions.ExcludeNothing || !filterResult.HasFlag(DBEntryFilterResultActions.ExcludeSelf))) { yield return(fileEntry); } } else { depth--; var poppedDir = dirs.Pop(); currentPath = poppedDir.ParentDirectory?.FullName ?? poppedDir.RootDirectory?.FullName ?? string.Empty; } typeAndAttributes = (DBEntryAttributes)binaryReader.ReadByte(); } var nullByte = binaryReader.ReadByte(); // normally its a dword byte but we should already have read a zero byte before if (nullByte != 0) { throw new ArchiveException($"Was expecting to read a final null-byte, read {nullByte} instead."); } // positionBeforeRead = inputStream.Position; currentPathStack.Pop(); positionBeforeReadRootDirectory = inputStream.Position; currentRootDirectory = DBRootDirectoryEntry.ReadFrom(binaryReader, strBuilder); // readLength = inputStream.Position - positionBeforeRead; } }