internal static DirectoryEntry Parse(BinaryReader reader) { byte[] nameValue = reader.ReadBytes(64); ushort nameLength = reader.ReadUInt16(); string name = null; if (nameLength > 1) { name = System.Text.Encoding.Unicode.GetString(nameValue, 0, nameLength - 2); } byte typeValue = reader.ReadByte(); DirectoryEntryType type = EnumUtil.ParseDirectoryEntryType(typeValue); byte colorValue = reader.ReadByte(); Color color = EnumUtil.ParseColor(colorValue); uint leftSiblingSid = reader.ReadUInt32(); uint rightSiblingSid = reader.ReadUInt32(); uint childSid = reader.ReadUInt32(); byte[] classId = reader.ReadBytes(16); uint userFlags = reader.ReadUInt32(); uint createdTimeLow = reader.ReadUInt32(); long createdTimeHigh = reader.ReadUInt32(); DateTime createdTime = new DateTime(); if (createdTimeHigh > 0) { long ticks = createdTimeLow + (createdTimeHigh << 32); DateTime year1601 = new DateTime(1601, 1, 1); try { createdTime = year1601.AddTicks(ticks).ToLocalTime(); } catch (Exception) //ignore wrong dates { } } uint lastModifiedTimeLow = reader.ReadUInt32(); long lastModifiedTimeHigh = reader.ReadUInt32(); DateTime lastModifiedTime = new DateTime(); if (lastModifiedTimeHigh > 0) { long ticks = lastModifiedTimeLow + (lastModifiedTimeHigh << 32); DateTime year1601 = new DateTime(1601, 1, 1); try { lastModifiedTime = year1601.AddTicks(ticks).ToLocalTime(); } catch (Exception) //ignore wrong dates { } } uint startSector = reader.ReadUInt32(); uint size = reader.ReadUInt32(); if (type == DirectoryEntryType.Root) { RootDirectoryEntry entry = new RootDirectoryEntry(); entry.type = DirectoryEntryType.Root; entry.name = name; entry.color = color; entry.leftSiblingSid = leftSiblingSid; entry.rightSiblingSid = rightSiblingSid; entry.childSid = childSid; entry.classId = classId; entry.userFlags = userFlags; entry.createdTime = createdTime; entry.lastModifiedTime = lastModifiedTime; entry.startSector = startSector; entry.size = size; return(entry); } else if (type == DirectoryEntryType.Stream) { Stream entry = new Stream(); entry.type = DirectoryEntryType.Stream; entry.name = name; entry.color = color; entry.leftSiblingSid = leftSiblingSid; entry.rightSiblingSid = rightSiblingSid; entry.childSid = childSid; entry.classId = classId; entry.userFlags = userFlags; entry.createdTime = createdTime; entry.lastModifiedTime = lastModifiedTime; entry.startSector = startSector; entry.size = size; return(entry); } else if (type == DirectoryEntryType.Storage) { Storage entry = new Storage(); entry.type = DirectoryEntryType.Storage; entry.name = name; entry.color = color; entry.leftSiblingSid = leftSiblingSid; entry.rightSiblingSid = rightSiblingSid; entry.childSid = childSid; entry.classId = classId; entry.userFlags = userFlags; entry.createdTime = createdTime; entry.lastModifiedTime = lastModifiedTime; entry.startSector = startSector; entry.size = size; return(entry); } else { Storage entry = new Storage(); entry.type = DirectoryEntryType.Invalid; entry.name = name; entry.color = color; entry.leftSiblingSid = leftSiblingSid; entry.rightSiblingSid = rightSiblingSid; entry.childSid = childSid; entry.classId = classId; entry.userFlags = userFlags; entry.createdTime = createdTime; entry.lastModifiedTime = lastModifiedTime; entry.startSector = startSector; entry.size = size; return(entry); } }
private void OpenImplementation(System.IO.Stream stream) { if (stream.Length < 512) { throw new InvalidFileFormatException("Invalid file format."); } BinaryReader reader = new BinaryReader(stream, System.Text.Encoding.Unicode); reader.BaseStream.Position = 0; header = new Header(reader); uint[] difat = ParseDifat(reader); uint[] fat = ParseFat(reader, difat); uint[] miniFat = null; if (header.FirstMiniFatSector != 0xFFFFFFFE) { miniFat = ParseMiniFat(reader, fat); } IList <uint> directoryChain = new List <uint>(); uint directorySector = header.FirstDirectorySector; directoryChain.Add(directorySector); while (true) { directorySector = fat[directorySector]; if (directorySector != 0xFFFFFFFE) { directoryChain.Add(directorySector); } else { break; } } MemoryStream directoryMemoryStream = new MemoryStream(); using (directoryMemoryStream) { BinaryReader directoryReader = new BinaryReader(directoryMemoryStream, System.Text.Encoding.Unicode); for (int i = 0; i < directoryChain.Count; i++) { uint currentDirectoryChain = directoryChain[i]; reader.BaseStream.Position = currentDirectoryChain * header.SectorSize + header.SectorSize; byte[] currentSector = reader.ReadBytes(header.SectorSize); directoryMemoryStream.Write(currentSector, 0, currentSector.Length); } directoryReader.BaseStream.Position = 0; root = (RootDirectoryEntry)DirectoryEntry.Parse(directoryReader); IDictionary <uint, DirectoryEntry> directoryEntries = new Dictionary <uint, DirectoryEntry>(); //read directory entries //////////////////////////////////////////////// directoryEntries.Add(0, root); if (root.childSid != 0xFFFFFFFF) { directoryReader.BaseStream.Position = root.childSid * 128; DirectoryEntry newEntry = DirectoryEntry.Parse(directoryReader); directoryEntries.Add(root.childSid, newEntry); root.directoryEntries.Add(newEntry); newEntry.parent = root; Stack <DirectoryEntry> leftStack = new Stack <DirectoryEntry>(); Stack <DirectoryEntry> rightStack = new Stack <DirectoryEntry>(); Stack <DirectoryEntry> childStack = new Stack <DirectoryEntry>(); leftStack.Push(newEntry); rightStack.Push(newEntry); childStack.Push(newEntry); while (leftStack.Count > 0 || rightStack.Count > 0 || childStack.Count > 0) { if (leftStack.Count > 0) { DirectoryEntry currentEntry = (DirectoryEntry)leftStack.Pop(); if (currentEntry.leftSiblingSid != 0xFFFFFFFF && !directoryEntries.ContainsKey(currentEntry.leftSiblingSid)) { directoryReader.BaseStream.Position = currentEntry.leftSiblingSid * 128; newEntry = DirectoryEntry.Parse(directoryReader); directoryEntries.Add(currentEntry.leftSiblingSid, newEntry); currentEntry.parent.directoryEntries.Add(newEntry); newEntry.parent = currentEntry.parent; leftStack.Push(newEntry); rightStack.Push(newEntry); childStack.Push(newEntry); continue; } } if (rightStack.Count > 0) { DirectoryEntry currentEntry = (DirectoryEntry)rightStack.Pop(); if (currentEntry.rightSiblingSid != 0xFFFFFFFF && !directoryEntries.ContainsKey(currentEntry.rightSiblingSid)) { directoryReader.BaseStream.Position = currentEntry.rightSiblingSid * 128; newEntry = DirectoryEntry.Parse(directoryReader); directoryEntries.Add(currentEntry.rightSiblingSid, newEntry); currentEntry.parent.directoryEntries.Add(newEntry); newEntry.parent = currentEntry.parent; leftStack.Push(newEntry); rightStack.Push(newEntry); childStack.Push(newEntry); continue; } } if (childStack.Count > 0) { DirectoryEntry currentEntry = (DirectoryEntry)childStack.Pop(); if (currentEntry.childSid != 0xFFFFFFFF && !directoryEntries.ContainsKey(currentEntry.childSid)) { directoryReader.BaseStream.Position = currentEntry.childSid * 128; newEntry = DirectoryEntry.Parse(directoryReader); directoryEntries.Add(currentEntry.childSid, newEntry); currentEntry.directoryEntries.Add(newEntry); newEntry.parent = currentEntry; leftStack.Push(newEntry); rightStack.Push(newEntry); childStack.Push(newEntry); } } } } //////////////////////////////////////////////// IList <DirectoryEntry> directoryEntriesList = new List <DirectoryEntry>(); foreach (DirectoryEntry entry in directoryEntries.Values) { if (entry == root) { directoryEntriesList.Insert(0, entry); } else { directoryEntriesList.Add(entry); } } MemoryStream miniStream = new MemoryStream(); using (miniStream) { BinaryReader miniStreamReader = new BinaryReader(miniStream); for (int i = 0; i < directoryEntriesList.Count; i++) { DirectoryEntry entry = directoryEntriesList[i]; if (entry.type != DirectoryEntryType.Storage) { if (entry.type != DirectoryEntryType.Root && entry.Size > 0 && entry.Size < header.MiniStreamMaxSize) { IList <uint> streamChain = new List <uint>(); uint streamSector = entry.startSector; streamChain.Add(streamSector); while (true) { streamSector = miniFat[streamSector]; if (streamSector != 0xFFFFFFFC && streamSector != 0xFFFFFFFD && streamSector != 0xFFFFFFFE && streamSector != 0xFFFFFFFF && streamSector != miniFat[streamSector]) { streamChain.Add(streamSector); } else { break; } } MemoryStream entryBufferMemoryStream = new MemoryStream(); using (entryBufferMemoryStream) { for (int j = 0; j < streamChain.Count; j++) { uint currentStreamChain = streamChain[j]; miniStreamReader.BaseStream.Position = currentStreamChain * 64; byte[] currentSector = miniStreamReader.ReadBytes(64); entryBufferMemoryStream.Write(currentSector, 0, currentSector.Length); } entry.buffer = new byte[entry.size]; if (entryBufferMemoryStream.Length < entry.buffer.Length) { entry.buffer = new byte[entryBufferMemoryStream.Length]; } System.Array.Copy(entryBufferMemoryStream.ToArray(), 0, entry.buffer, 0, entry.buffer.Length); } } else if (entry.Size > 0) { IList <uint> streamChain = new List <uint>(); uint streamSector = entry.startSector; streamChain.Add(streamSector); while (true) { streamSector = fat[streamSector]; if (streamSector != 0xFFFFFFFC && streamSector != 0xFFFFFFFD && streamSector != 0xFFFFFFFE && streamSector != 0xFFFFFFFF && streamSector != fat[streamSector]) { streamChain.Add(streamSector); } else { break; } } MemoryStream entryBufferMemoryStream = new MemoryStream(); using (entryBufferMemoryStream) { for (int j = 0; j < streamChain.Count; j++) { uint currentStreamChain = streamChain[j]; reader.BaseStream.Position = currentStreamChain * header.SectorSize + header.SectorSize; byte[] currentSector = reader.ReadBytes(header.SectorSize); entryBufferMemoryStream.Write(currentSector, 0, currentSector.Length); } entry.buffer = new byte[entry.Size]; if (entryBufferMemoryStream.Length < entry.buffer.Length) { entry.buffer = new byte[entryBufferMemoryStream.Length]; } System.Array.Copy(entryBufferMemoryStream.ToArray(), 0, entry.buffer, 0, entry.buffer.Length); } if (entry == root) { if (root.buffer != null) { miniStream.Write(root.buffer, 0, root.buffer.Length); } } } } } } } }