internal IEnumerable <RarFilePart> GetVolumeFileParts() { MarkHeader lastMarkHeader = null; foreach (var header in _headerFactory.ReadHeaders(Stream)) { switch (header.HeaderType) { case HeaderType.Mark: { lastMarkHeader = header as MarkHeader; } break; case HeaderType.Archive: { ArchiveHeader = header as ArchiveHeader; } break; case HeaderType.File: { var fh = header as FileHeader; yield return(CreateFilePart(lastMarkHeader, fh)); } break; } } }
internal static IEnumerable <RarArchiveVolume> GetParts(FileInfo fileInfo, RarOptions options) { var part = new FileInfoRarArchiveVolume(fileInfo, options); yield return(part); if (!part.ArchiveHeader.ArchiveHeaderFlags.HasFlag(ArchiveFlags.VOLUME)) { yield break; //if file isn't volume then there is no reason to look } ArchiveHeader ah = part.ArchiveHeader; fileInfo = GetNextFileInfo(ah, part.FileParts.FirstOrDefault() as FileInfoRarFilePart); //we use fileinfo because rar is dumb and looks at file names rather than archive info for another volume while (fileInfo != null) { part = new FileInfoRarArchiveVolume(fileInfo, options); fileInfo = GetNextFileInfo(ah, part.FileParts.FirstOrDefault() as FileInfoRarFilePart); if (!fileInfo.Exists) { yield break; } yield return(part); } }
public static bool IsArchiveFile(Stream stream) { using (EndianReader reader = new EndianReader(stream, EndianType.BigEndian)) { return(ArchiveHeader.IsArchiveHeader(reader)); } }
public static ArchiveHeader Create(FileSplitInfo fileSplitInfo) { var header = new ArchiveHeader(fileSplitInfo.ChunkCount); for (int id = 0; id < fileSplitInfo.ChunkCount; id++) { header.ChunkLengths[id] = fileSplitInfo.Chunks[id].Length; } return header; }
public static bool IsArchiveFile(Stream stream, long offset, long size) { using (PartialStream bundleStream = new PartialStream(stream, offset, size)) { using (EndianReader reader = new EndianReader(bundleStream, EndianType.BigEndian)) { return(ArchiveHeader.IsArchiveHeader(reader)); } } }
public NARC() { Header = new ArchiveHeader(); FATB = new FileAllocationTableBlock(); FNTB = new FilenameTableBlock(); FIMG = new FileImageBlock(); FromFileSystem(new SFSDirectory("/", true) { DirectoryID = 0xF000 }); }
public Archive(Stream stream) { byte[] header = new byte[4]; stream.Read(header, 0, 4); stream.Seek(-4, SeekOrigin.Current); if (header[0] == 'Y') { archiveFileStream = new Yaz0Stream(stream); } else { archiveFileStream = stream; } using (EndianBinaryReader er = new EndianBinaryReader(archiveFileStream, Encoding.ASCII, true, Endian.Big)) { archiveHeader = new ArchiveHeader(er); sfatHeader = new SFATHeader(er); sfatEntries = new SFATEntry[sfatHeader.NodeCount]; for (int i = 0; i < sfatHeader.NodeCount; i++) { sfatEntries[i] = new SFATEntry(er); } er.Skip(8); // SFNT, 0x00, 0x08, 0x00, 0x00 sfatStringTable = new string[sfatHeader.NodeCount]; for (int i = 0; i < sfatHeader.NodeCount; i++) { // These strings are aligned to 4 bytes. //while (er.PeekReadByte() == 0) // er.ReadByte(); sfatStringTable[i] = Encoding.ASCII.GetString(er.ReadBytesUntil(0)); } } for (int i = 0; i < sfatEntries.Length; i++) { sfatEntries[i].FileName = sfatStringTable[sfatEntries[i].FileNameTableOffset / 4]; } fileDictionary = new Dictionary <string, ArchiveEntry>(sfatEntries.Length); for (int i = 0; i < sfatEntries.Length; i++) { string name = sfatStringTable[sfatEntries[i].FileNameTableOffset / 4]; uint size = sfatEntries[i].DataOffsetEnd - sfatEntries[i].DataOffsetStart; fileDictionary.Add(name, new ArchiveEntry(name, sfatEntries[i].DataOffsetStart + archiveHeader.DataOffset, size, sfatEntries[i].FileType)); } }
private static FileInfo GetNextFileInfo(ArchiveHeader ah, FileInfoRarFilePart currentFilePart) { if (currentFilePart == null) { return(null); } bool oldNumbering = !ah.ArchiveHeaderFlags.HasFlag(ArchiveFlags.NEWNUMBERING) || currentFilePart.MarkHeader.OldFormat; if (oldNumbering) { return(FindNextFileWithOldNumbering(currentFilePart.FileInfo)); } else { return(FindNextFileWithNewNumbering(currentFilePart.FileInfo)); } }
private static FileInfo GetNextFileInfo(ArchiveHeader ah, FileInfoRarFilePart currentFilePart) { if (currentFilePart == null) { return(null); } bool oldNumbering = ah.OldNumberingFormat || currentFilePart.MarkHeader.OldNumberingFormat; if (oldNumbering) { return(FindNextFileWithOldNumbering(currentFilePart.FileInfo)); } else { return(FindNextFileWithNewNumbering(currentFilePart.FileInfo)); } }
public NARC(byte[] Data) { EndianBinaryReader er = new EndianBinaryReader(new MemoryStream(Data), Endianness.LittleEndian); try { Header = new ArchiveHeader(er); FATB = new FileAllocationTableBlock(er); FNTB = new FilenameTableBlock(er); FIMG = new FileImageBlock(er); } catch (SignatureNotCorrectException e) { MessageBox.Show(e.ToString(), "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); } finally { er.Close(); } }
internal static IEnumerable <RarVolume> GetParts(FileInfo fileInfo, ReaderOptions options) { FileInfoRarArchiveVolume part = new FileInfoRarArchiveVolume(fileInfo, options); yield return(part); ArchiveHeader ah = part.ArchiveHeader; if (!ah.IsVolume) { yield break; //if file isn't volume then there is no reason to look } fileInfo = GetNextFileInfo(ah, part.FileParts.FirstOrDefault() as FileInfoRarFilePart); //we use fileinfo because rar is dumb and looks at file names rather than archive info for another volume while (fileInfo != null && fileInfo.Exists) { part = new FileInfoRarArchiveVolume(fileInfo, options); fileInfo = GetNextFileInfo(ah, part.FileParts.FirstOrDefault() as FileInfoRarFilePart); yield return(part); } }
public bool MoveNext() { var result = files.MoveNext(); if (result) { var fi = new FileInfo(files.Current); Current = new ArchiveHeader { ArchiveName = archivename, FileAttributes = fi.Attributes, FileName = fi.Name, FileTime = fi.LastWriteTime, UnpackedSize = fi.Length, PackedSize = fi.Length, }; } else { Current = null; } return(result); }
internal static IEnumerable <RarVolume> GetParts(FileInfo fileInfo, string password, Options options) { FileInfoRarArchiveVolume part = new FileInfoRarArchiveVolume(fileInfo, password, options); yield return(part); ArchiveFlags af = part.ArchiveHeader.ArchiveHeaderFlags; if (!af_HasFlag(af, ArchiveFlags.VOLUME)) { yield break; //if file isn't volume then there is no reason to look } ArchiveHeader ah = part.ArchiveHeader; fileInfo = GetNextFileInfo(ah, part.FileParts.FirstOrDefault <RarFilePart>() as FileInfoRarFilePart); //we use fileinfo because rar is dumb and looks at file names rather than archive info for another volume while (fileInfo != null && fileInfo.Exists) { part = new FileInfoRarArchiveVolume(fileInfo, password, options); fileInfo = GetNextFileInfo(ah, part.FileParts.FirstOrDefault <RarFilePart>() as FileInfoRarFilePart); yield return(part); } }
public static void Main(string[] args) { bool showHelp = false; bool overwriteFiles = false; bool noCrypto = false; bool verbose = false; var options = new OptionSet() { { "no-crypto", "don't use any encryption", v => noCrypto = v != null }, { "o|overwrite", "overwrite existing files", v => overwriteFiles = v != null }, { "v|verbose", "be verbose", v => verbose = v != null }, { "h|help", "show this message and exit", v => showHelp = v != null }, }; List <string> extras; try { extras = options.Parse(args); } catch (OptionException e) { Console.Write("{0}: ", GetExecutableName()); Console.WriteLine(e.Message); Console.WriteLine("Try `{0} --help' for more information.", GetExecutableName()); return; } if (extras.Count < 1 || extras.Count > 2 || showHelp == true) { Console.WriteLine("Usage: {0} [OPTIONS]+ input_ipf [output_dir]", GetExecutableName()); Console.WriteLine(); Console.WriteLine("Options:"); options.WriteOptionDescriptions(Console.Out); return; } var inputPath = Path.GetFullPath(extras[0]); var outputPath = extras.Count > 1 ? extras[1] : Path.ChangeExtension(inputPath, null) + "_unpack"; const Endian endian = Endian.Little; using (var input = File.OpenRead(inputPath)) { if (input.Length < ArchiveHeader.Size) { throw new FormatException(); } input.Seek(-ArchiveHeader.Size, SeekOrigin.End); var header = ArchiveHeader.Read(input, endian); if (header.Magic != ArchiveHeader.Signature) { throw new FormatException(); } var fileEntries = new ArchiveFileEntry[header.FileTableCount]; if (header.FileTableCount > 0) { input.Position = header.FileTableOffset; for (int i = 0; i < header.FileTableCount; i++) { fileEntries[i] = ArchiveFileEntry.Read(input, endian); } } var deletionEntries = new ArchiveDeletionEntry[header.DeletionTableCount]; if (header.DeletionTableCount > 0) { input.Position = header.DeletionTableOffset; for (int i = 0; i < header.DeletionTableCount; i++) { deletionEntries[i] = ArchiveDeletionEntry.Read(input, endian); } } long current = 0; long total = fileEntries.Length; var padding = total.ToString(CultureInfo.InvariantCulture).Length; if (header.DeletionTableCount > 0) { Directory.CreateDirectory(outputPath); using (var output = File.Create(Path.Combine(outputPath, "deletions.json"))) using (var streamWriter = new StreamWriter(output)) using (var writer = new JsonTextWriter(streamWriter)) { writer.Indentation = 2; writer.IndentChar = ' '; writer.Formatting = Formatting.Indented; writer.WriteStartArray(); foreach (var deletionEntry in deletionEntries) { writer.WriteStartObject(); writer.WritePropertyName("archive"); writer.WriteValue(deletionEntry.Archive); writer.WritePropertyName("name"); writer.WriteValue(deletionEntry.Name); writer.WriteEndObject(); } writer.WriteEndArray(); } } foreach (var entry in fileEntries) { current++; var entryPath = Path.Combine(outputPath, entry.Archive.Replace('/', Path.DirectorySeparatorChar), entry.Name.Replace('/', Path.DirectorySeparatorChar)); if (overwriteFiles == false && File.Exists(entryPath) == true) { continue; } if (verbose == true) { Console.WriteLine("[{0}/{1}] {2}", current.ToString(CultureInfo.InvariantCulture).PadLeft(padding), total, entry.Name); } input.Seek(entry.Offset, SeekOrigin.Begin); var entryDirectory = Path.GetDirectoryName(entryPath); if (entryDirectory != null) { Directory.CreateDirectory(entryDirectory); } using (var output = File.Create(entryPath)) { input.Seek(entry.Offset, SeekOrigin.Begin); if (entry.ShouldCompress == false) { output.WriteFromStream(input, entry.CompressedSize); } else { var bytes = input.ReadBytes(entry.CompressedSize); if (noCrypto == false) { var crypto = new ArchiveCrypto(); crypto.Decrypt(bytes, 0, bytes.Length); } using (var temp = new MemoryStream(bytes, false)) { var zlib = new InflaterInputStream(temp, new Inflater(true)); output.WriteFromStream(zlib, entry.UncompressedSize); } } } } } }
public Archive(ArchiveHeader ArchiveHeader = default, slice <ptr <Member> > Members = default, io.Closer closer = default) { this.m_ArchiveHeaderRef = new ptr <ArchiveHeader>(ArchiveHeader); this.Members = Members; this.closer = closer; }
public static IEnumerable <ImportInfo> GetImportInfos(string libPath) { using FileStream libStream = new FileStream(libPath, FileMode.Open, FileAccess.Read); using BinaryReader libReader = new BinaryReader(libStream); byte[] libHeader = libReader.ReadBytes(expectedLibHeader.Length); if (!libHeader.SequenceEqual(expectedLibHeader)) { throw new InvalidOperationException($"{libPath} is not a valid .lib."); } long nextArchPos = libStream.Position; while (libStream.Position != libStream.Length) { libStream.Position = nextArchPos; // Make sure it starts on an even boundary if ((libStream.Position % 2) == 1) { libStream.Position += 1; } byte[] headerBytes = libReader.ReadBytes(Marshal.SizeOf(typeof(ArchiveHeader))); ArchiveHeader header = GetStructFromBytes <ArchiveHeader>(headerBytes); if (!header.IsValid) { yield break; } nextArchPos = libStream.Position + header.ArchiveSize; string name = header.Name; // We don't need these archives if (name == "/" || name == "//") { continue; } if (header.ArchiveSize < Marshal.SizeOf(typeof(ImportHeader))) { continue; } byte[] importHeaderBytes = libReader.ReadBytes(Marshal.SizeOf(typeof(ImportHeader))); ImportHeader importHeader = GetStructFromBytes <ImportHeader>(importHeaderBytes); // Is this really an import header? if (importHeader.sig1 != 0 || importHeader.sig2 != 0xFFFF) { continue; } // Make sure it's a code import if (importHeader.ImportType != ImportType.Code) { continue; } string symbolName = ReadNullTermString(libReader); string dllName = ReadNullTermString(libReader); string procName = symbolName; // If it's x86, try to undecorate it if (importHeader.MachineType == MachineType.X86) { if (procName.StartsWith('_')) { procName = procName.Substring(1); int atIndex = procName.IndexOf('@'); if (atIndex != -1) { procName = procName.Substring(0, atIndex); } } } yield return(new ImportInfo(dllName, procName)); } }
public static void Main(string[] args) { bool showHelp = false; bool verbose = false; bool noCrypto = false; var options = new OptionSet() { { "no-crypto", "don't use any encryption", v => noCrypto = v != null }, { "v|verbose", "be verbose", v => verbose = v != null }, { "h|help", "show this message and exit", v => showHelp = v != null }, }; List <string> extras; try { extras = options.Parse(args); } catch (OptionException e) { Console.Write("{0}: ", GetExecutableName()); Console.WriteLine(e.Message); Console.WriteLine("Try `{0} --help' for more information.", GetExecutableName()); return; } if (extras.Count < 1 || extras.Count > 2 || showHelp == true) { Console.WriteLine("Usage: {0} [OPTIONS]+ input_dir [output_dir]", GetExecutableName()); Console.WriteLine(); Console.WriteLine("Options:"); options.WriteOptionDescriptions(Console.Out); return; } const Endian endian = Endian.Little; var inputPath = Path.GetFullPath(extras[0]); var outputPath = extras.Count > 1 ? extras[1] : Path.ChangeExtension(inputPath, null) + "_unpack"; var archiveInfosUnsorted = new List <ArchiveInfo>(); var basePathInfo = new List <KeyValuePair <string, string> >(); basePathInfo.Add(new KeyValuePair <string, string>(Path.Combine(inputPath, "data"), "*.ipf")); basePathInfo.Add(new KeyValuePair <string, string>(Path.Combine(inputPath, "patch"), "*_001001.ipf")); foreach (var kv in basePathInfo) { var basePath = kv.Key; var filter = kv.Value; if (Directory.Exists(basePath) == false) { continue; } foreach (var archivePath in Directory.GetFiles(basePath, filter)) { using (var input = File.OpenRead(archivePath)) { if (input.Length < ArchiveHeader.Size) { throw new FormatException(); } input.Seek(-ArchiveHeader.Size, SeekOrigin.End); var header = ArchiveHeader.Read(input, endian); if (header.Magic != ArchiveHeader.Signature) { throw new FormatException(); } archiveInfosUnsorted.Add( new ArchiveInfo(archivePath, header.BaseRevision, header.Revision, header.FileTableCount + header.DeletionTableCount)); } } } var archiveInfos = archiveInfosUnsorted.OrderBy(ai => ai.BaseRevision) .ThenBy(ai => ai.Revision) .ThenBy(ai => ai.Path) .ToList(); long current = 0; long total = archiveInfos.Sum(ai => ai.TotalCount); var padding = total.ToString(CultureInfo.InvariantCulture).Length; var dataPaths = new Dictionary <string, List <string> >(); foreach (var archiveInfo in archiveInfos) { using (var input = File.OpenRead(archiveInfo.Path)) { if (input.Length < ArchiveHeader.Size) { throw new FormatException(); } input.Seek(-ArchiveHeader.Size, SeekOrigin.End); var header = ArchiveHeader.Read(input, endian); if (header.Magic != ArchiveHeader.Signature) { throw new FormatException(); } var fileEntries = new ArchiveFileEntry[header.FileTableCount]; if (header.FileTableCount > 0) { input.Position = header.FileTableOffset; for (int i = 0; i < header.FileTableCount; i++) { fileEntries[i] = ArchiveFileEntry.Read(input, endian); } } var deletionEntries = new ArchiveDeletionEntry[header.DeletionTableCount]; if (header.DeletionTableCount > 0) { input.Position = header.DeletionTableOffset; for (int i = 0; i < header.DeletionTableCount; i++) { deletionEntries[i] = ArchiveDeletionEntry.Read(input, endian); } } foreach (var entry in deletionEntries) { current++; if (entry.Archive == "data") { var dataPath = entry.Name.ToLowerInvariant(); if (dataPaths.ContainsKey(dataPath) == false) { // probably an incorrect entry pointing to a directory continue; } foreach (var entryPath in dataPaths[dataPath]) { if (File.Exists(entryPath) == true) { File.Delete(entryPath); } } dataPaths.Remove(entry.Name); } else { throw new NotImplementedException(); var entryPath = Path.Combine(outputPath, entry.Archive, entry.Name); if (File.Exists(entryPath) == true) { File.Delete(entryPath); } } } foreach (var entry in fileEntries) { current++; var entryPath = Path.Combine(outputPath, entry.Archive.Replace('/', Path.DirectorySeparatorChar), entry.Name.Replace('/', Path.DirectorySeparatorChar)); var dataPath = entry.Name.ToLowerInvariant(); if (dataPaths.ContainsKey(dataPath) == false) { dataPaths[dataPath] = new List <string>(); } if (dataPaths[dataPath].Contains(entryPath) == false) { dataPaths[dataPath].Add(entryPath); } if (verbose == true) { Console.WriteLine("[{0}/{1}] {2}/{3}", current.ToString(CultureInfo.InvariantCulture).PadLeft(padding), total, entry.Archive, entry.Name); } input.Seek(entry.Offset, SeekOrigin.Begin); var entryDirectory = Path.GetDirectoryName(entryPath); if (entryDirectory != null) { Directory.CreateDirectory(entryDirectory); } using (var output = File.Create(entryPath)) { input.Seek(entry.Offset, SeekOrigin.Begin); if (entry.ShouldCompress == false) { output.WriteFromStream(input, entry.CompressedSize); } else { var bytes = input.ReadBytes(entry.CompressedSize); if (noCrypto == false) { var crypto = new ArchiveCrypto(); crypto.Decrypt(bytes, 0, bytes.Length); } using (var temp = new MemoryStream(bytes, false)) { var zlib = new InflaterInputStream(temp, new Inflater(true)); output.WriteFromStream(zlib, entry.UncompressedSize); } } } } } } }
private ArchiveHeader ReadArchiveHeader(BinaryReader rd) { UInt16 id = rd.ReadUInt16(); byte[] BasicHeader; ArchiveHeader result = new ArchiveHeader(); BinaryReader hr; if (id != 0xea60) return null; result.BasicHeaderSize = rd.ReadUInt16(); if (result.BasicHeaderSize > 2600) return null; BasicHeader = new byte[result.BasicHeaderSize]; rd.Read(BasicHeader, 0, result.BasicHeaderSize); result.BasicHeaderCRC = rd.ReadUInt32(); // read/skip extended headers UInt16 extHdrSize = rd.ReadUInt16(); // TODO: check if extended header occurs at all in any archive if (extHdrSize > 0) { for (int i = 0; i < extHdrSize; i++) rd.ReadByte(); } hr = new BinaryReader(new MemoryStream(BasicHeader)); result.FirstHeaderSize = hr.ReadByte(); result.ArchiverVersion = hr.ReadByte(); result.MinVersionToExtract = hr.ReadByte(); result.HostOS = hr.ReadByte(); result.ARJFlags = hr.ReadByte(); if ((result.ARJFlags & 0x4d) != 0) return null; // unsupported archive flags (protected, multi-volume, garbled, secured) result.SecurityVersion = hr.ReadByte(); result.FileType = hr.ReadByte(); if (result.FileType != 2) return null; hr.ReadByte(); // reserved result.ArchiveCreated = FromDOSDateTime(hr.ReadUInt32()); result.ArchiveModified = FromDOSDateTime(hr.ReadUInt32()); result.ArchiveSize = hr.ReadUInt32(); result.SecurityEnvelopePosition = hr.ReadUInt32(); result.FilespecPosition = hr.ReadUInt16(); result.SecurityEnvelopeLength = hr.ReadUInt16(); result.Encryption = hr.ReadByte(); if (result.Encryption != 0) return null; // encrypted archives not supported result.LastChapter = hr.ReadByte(); // skip over "extra data" for (int i = 0; i < result.FirstHeaderSize - 0x1e; i++) hr.ReadByte(); // ignore extra data result.OriginalFileName = ReadASCIIZ(hr); result.Comment = ReadASCIIZ(hr); if (result.BasicHeaderSize != result.FirstHeaderSize + result.OriginalFileName.Length + result.Comment.Length + 2) return null; ulong crc = CRCCalculator.CalculateCRC(BasicHeader, BasicHeader.Length); // in the end, this should catch all false positives :) if (crc != result.BasicHeaderCRC) return null; return result; }