diff --git a/SabreTools.Helper/Data/Structs.cs b/SabreTools.Helper/Data/Structs.cs index 2f37f94c..b040f72c 100644 --- a/SabreTools.Helper/Data/Structs.cs +++ b/SabreTools.Helper/Data/Structs.cs @@ -472,4 +472,45 @@ namespace SabreTools.Helper } #endregion + + #region Archive structs + + /// + /// Intermediate struct for holding zip archive information + /// + public struct ZipArchiveStruct + { + public string FileName; + public string Comment; + public bool Zip64; + + public List Entries; + public int SOCDOffset; + public int EOCDOffset; + public int CentralDirectoryCRC; + } + + /// + /// Intermediate struct for holding zip archive entry information + /// + public struct ZipArchiveEntryStruct + { + public short VersionMadeBy; + public short VersionNeeded; + public short GeneralPurposeFlag; + public short CompressionMethod; + public short LastModFileTime; + public short LastModFileDate; + public int CRC; + public int CompressedSize; + public int UncompressedSize; + public string FileName; + public string ExtraField; + public string Comment; + public short InternalFileAttributes; + public int ExternalFileAttributes; + public int RelativeOffset; + } + + #endregion } diff --git a/SabreTools.Helper/Tools/FileTools.cs b/SabreTools.Helper/Tools/FileTools.cs index 7661e1ef..d4e5c6a0 100644 --- a/SabreTools.Helper/Tools/FileTools.cs +++ b/SabreTools.Helper/Tools/FileTools.cs @@ -425,6 +425,34 @@ namespace SabreTools.Helper return success; } + ZipArchiveStruct zas = ReadCentralDirectory(inputArchive, logger); + Console.WriteLine("Archive Filename: " + zas.FileName); + Console.WriteLine("Archive Comment: " + zas.Comment.Length + " " + zas.Comment); + Console.WriteLine("Archive Central Directory CRC: " + zas.CentralDirectoryCRC.ToString("X8")); + Console.WriteLine(); + Console.WriteLine("Entries:"); + foreach (ZipArchiveEntryStruct zaes in zas.Entries) + { + Console.WriteLine("Entry Filename: " + zaes.FileName.Length + " " + zaes.FileName); + Console.WriteLine("Entry Comment: " + zaes.Comment.Length + " " + zaes.Comment); + Console.WriteLine("Entry Compressed Size: " + zaes.CompressedSize); + Console.WriteLine("Entry Compression Method: " + zaes.CompressionMethod); + Console.WriteLine("Entry CRC: " + zaes.CRC.ToString("X8")); + Console.WriteLine("Entry External File Attributes: " + zaes.ExternalFileAttributes); + Console.WriteLine("Entry Extra Field: " + zaes.ExtraField.Length + " " + zaes.ExtraField); + Console.WriteLine("Entry General Purpose Flag: " + zaes.GeneralPurposeFlag); + Console.WriteLine("Entry Internal File Attributes: " + zaes.InternalFileAttributes); + Console.WriteLine("Entry Last Modification File Date: " + zaes.LastModFileDate); + Console.WriteLine("Entry Last Modification File Time: " + zaes.LastModFileTime); + Console.WriteLine("Entry Relative Offset: " + zaes.RelativeOffset); + Console.WriteLine("Entry Uncompressed Size: " + zaes.UncompressedSize); + Console.WriteLine("Entry Version Made By: " + zaes.VersionMadeBy); + Console.WriteLine("Entry Version Needed: " + zaes.VersionNeeded); + Console.WriteLine(); + } + Console.ReadLine(); + + /* ZipArchive outarchive = null; try { @@ -479,6 +507,7 @@ namespace SabreTools.Helper { outarchive?.Dispose(); } + */ return success; } @@ -858,6 +887,118 @@ namespace SabreTools.Helper } } + /// + /// Read the current directory record + /// + /// Name of the input file to check + /// Logger object for file and console output + /// This does not do any handling for Zip64 currently + public static ZipArchiveStruct ReadCentralDirectory(string input, Logger logger) + { + // Create the zip archive struct to hold all of the information + ZipArchiveStruct zas = new ZipArchiveStruct + { + FileName = Path.GetFileNameWithoutExtension(input), + Entries = new List(), + }; + + int position = -1; + + // Seek backwards to find the EOCD pattern + using (BinaryReader br = new BinaryReader(File.OpenRead(input))) + { + int sig = 101010256; + int read = 0; + int index = -5; + while (sig != read && (-index) < new FileInfo(input).Length) + { + br.BaseStream.Seek(index, SeekOrigin.End); + read = br.ReadInt32(); + index--; + } + + // If we found the signature, then set the correct position + if (sig == read) + { + position = (int)br.BaseStream.Position - 4; + } + } + + // If we found the EOCD, get all of the information out of that area + if (position != -1) + { + zas.EOCDOffset = (int)position; + using (BinaryReader br = new BinaryReader(File.OpenRead(input))) + { + br.BaseStream.Seek(position, SeekOrigin.Begin); + br.ReadInt32(); // end of central dir signature + br.ReadInt16(); // number of this disk + br.ReadInt16(); // number of the disk with the start of the central directory + br.ReadInt16(); // total number of entries in the central directory on this disk + br.ReadInt16(); // total number of entries in the central directory + br.ReadInt32(); // size of the central directory + position = br.ReadInt32(); // offset of start of central directory with respect to the starting disk number + int commentlength = br.ReadInt16(); + zas.Comment = Style.ConvertHex(BitConverter.ToString(br.ReadBytes(commentlength))); + } + } + + // If we found the SOCD, get all of the information out of that area + if (position != -1 && position != zas.EOCDOffset) + { + zas.SOCDOffset = position; + using (BinaryReader br = new BinaryReader(File.OpenRead(input))) + { + int temp = 0; + while (temp != 84233040 /* digital signature */ && temp != 101010256 /* eocd */) + { + ZipArchiveEntryStruct zaes = new ZipArchiveEntryStruct(); + + br.BaseStream.Seek(position, SeekOrigin.Begin); + br.ReadInt32(); // central file header signature + zaes.VersionMadeBy = br.ReadInt16(); + zaes.VersionNeeded = br.ReadInt16(); + zaes.GeneralPurposeFlag = br.ReadInt16(); + zaes.CompressionMethod = br.ReadInt16(); + zaes.LastModFileTime = br.ReadInt16(); + zaes.LastModFileDate = br.ReadInt16(); + zaes.CRC = br.ReadInt32(); + zaes.CompressedSize = br.ReadInt32(); + zaes.UncompressedSize = br.ReadInt32(); + int fileNameLength = br.ReadInt16(); + int extraFieldLength = br.ReadInt16(); + int fileCommentLength = br.ReadInt16(); + br.ReadInt16(); // disk number start + zaes.InternalFileAttributes = br.ReadInt16(); + zaes.ExternalFileAttributes = br.ReadInt32(); + zaes.RelativeOffset = br.ReadInt32(); + zaes.FileName = Style.ConvertHex(BitConverter.ToString(br.ReadBytes(fileNameLength))); + zaes.ExtraField = Style.ConvertHex(BitConverter.ToString(br.ReadBytes(extraFieldLength))); + zaes.Comment = Style.ConvertHex(BitConverter.ToString(br.ReadBytes(fileCommentLength))); + position += 46 + fileNameLength + extraFieldLength + fileCommentLength; + temp = br.ReadInt32(); + zas.Entries.Add(zaes); + } + } + } + + // Finally, get a hash of the entire central directory (between SOCD and EOCD) + if (zas.SOCDOffset > 0 && zas.EOCDOffset > 0) + { + using (BinaryReader br = new BinaryReader(File.OpenRead(input))) + { + br.BaseStream.Seek(zas.SOCDOffset, SeekOrigin.Begin); + byte[] cd = br.ReadBytes(zas.EOCDOffset - zas.SOCDOffset); + + OptimizedCRC ocrc = new OptimizedCRC(); + ocrc.Update(cd, 0, cd.Length); + zas.CentralDirectoryCRC = ocrc.Value; + } + } + + return zas; + } + #endregion #region File Manipulation diff --git a/SabreTools.Helper/Tools/Style.cs b/SabreTools.Helper/Tools/Style.cs index 7d386aa6..05211183 100644 --- a/SabreTools.Helper/Tools/Style.cs +++ b/SabreTools.Helper/Tools/Style.cs @@ -525,6 +525,27 @@ namespace SabreTools.Helper return s; } + /// + /// http://stackoverflow.com/questions/5613279/c-sharp-hex-to-ascii + /// + public static string ConvertHex(String hexString) + { + if (hexString.Contains("-")) + { + hexString = hexString.Replace("-", ""); + } + + StringBuilder sb = new StringBuilder(); + + for (int i = 0; i < hexString.Length; i += 2) + { + String hs = hexString.Substring(i, 2); + sb.Append(Convert.ToChar(Convert.ToUInt32(hs, 16))); + } + + return sb.ToString(); + } + #endregion } }