private void Optimize(ArchiveInformationView view) { ArchiveOptimizer optimizer = null; ArchiveInformation newInfo = null; Dispatcher.Invoke(() => { newInfo = view.Info; optimizer = new ArchiveOptimizer(view.Info); view.StartProgress(); optimizer.Progress += view.OnProgress; }); try { newInfo = optimizer.Optimize(); } catch (Exception ex) { UIHelper.ShowError(ex); } Dispatcher.Invoke(() => { view.Info = newInfo; view.StopProgress(); }); }
private void LoadOptions() { try { ContinueButton.IsEnabled = false; ObservableCollection <ArchiveInformationView> archiveCollection = ArchivesList.Archives; foreach (string archivePath in Options.GetGameArchivesPaths()) { ArchiveInformationAccessor accessor = new ArchiveInformationAccessor(archivePath); ArchiveInformation info = accessor.ReadOrCreate(); ArchiveInformationView view = new ArchiveInformationView(info); archiveCollection.Add(view); } ReserveControl.AbsoluteValue = Options.AbsoluteReserve; ReserveControl.RelativeValue = Options.RelativeReserve; ContinueButton.IsEnabled = true; } catch (Exception ex) { UIHelper.ShowError(ex); } }
public ArchiveInformationView(ArchiveInformation info) { Exceptions.CheckArgumentNull(info, "info"); Info = info; Refresh(); }
public void ParserTest(string archive, string truePlace, string trueParish) { var ai = ArchiveInformation.Parse(archive); Assert.NotNull(ai); Assert.AreEqual(archive, ai.Archive); Assert.AreEqual(truePlace, ai.Place); Assert.AreEqual(trueParish, ai.Parish); }
/// <summary> /// Reads the contents of the archive's Central Directory and returns an ArchiveInformation record with the /// CompressedSize and UncompressedSize fields populated from the contents of the Central Directory file header /// records. /// </summary> /// <param name="eocdRecord">The End of Central Directory record which gives us information about the Central Directory's location</param> /// <returns>The pre-populated ArchiveInformation record</returns> /// <exception cref="InvalidArchiveException"></exception> private ArchiveInformation ReadCentralDirectoryContents(ZipEndOfCentralDirectoryRecord eocdRecord) { // -- Get a new info record ArchiveInformation info = new ArchiveInformation(); info.UncompressedSize = 0; info.CompressedSize = 0; // -- Open the correct archive part and seek to the first Central Directory record Open(eocdRecord.CDDisk + 1); InputStream.Seek((long)eocdRecord.CDOffset, SeekOrigin.Begin); // -- Loop all entries for (int i = 0; i < eocdRecord.NumFilesInCD; i++) { ZipCentralDirectoryFileHeader cdHeader = new ZipCentralDirectoryFileHeader(); cdHeader.Signature = ReadULong(); if (cdHeader.Signature != BitConverter.ToUInt32(new byte[] { 0x50, 0x4b, 0x01, 0x02 }, 0)) { throw new InvalidArchiveException(String.Format(Language.ResourceManager.GetString("ERR_FORMAT_INVALID_CD_HEADER_AT_POSITION"), CurrentPartNumber, InputStream.Position - 4)); } cdHeader.VersionMadeBy = ReadUShort(); cdHeader.VersionToExtract = ReadUShort(); cdHeader.Flags = ReadUShort(); cdHeader.CompressionMethod = ReadUShort(); cdHeader.LastModTime = ReadUShort(); cdHeader.LastModDate = ReadUShort(); cdHeader.CRC32 = ReadULong(); cdHeader.CompressedSize = ReadULong(); cdHeader.UncompressedSize = ReadULong(); cdHeader.FileNameLength = ReadUShort(); cdHeader.ExtraFieldLength = ReadUShort(); cdHeader.FileCommentLength = ReadUShort(); cdHeader.DiskNumberStart = ReadUShort(); cdHeader.InternalFileAttributes = ReadUShort(); cdHeader.ExternalFileAttributes = ReadULong(); cdHeader.RelativeOffset = ReadULong(); cdHeader.Filename = ReadUtf8String(cdHeader.FileNameLength); cdHeader.Comment = ""; if (cdHeader.FileCommentLength > 0) { cdHeader.Comment = ReadUtf8String(cdHeader.FileCommentLength); } info.CompressedSize += cdHeader.CompressedSize; info.UncompressedSize += cdHeader.UncompressedSize; } return(info); }
/// <summary> /// Read the main header of the archive. /// </summary> /// <returns> /// The main header of the archive /// </returns> public JpaArchiveHeader ReadArchiveHeader() { JpaArchiveHeader archiveHeader = new JpaArchiveHeader(); // Initialize parts counter archiveHeader.TotalParts = 1; // Open the first part Open(1); archiveHeader.Signature = ReadAsciiString(3); if (archiveHeader.Signature != "JPA") { throw new InvalidArchiveException(String.Format(Language.ResourceManager.GetString("ERR_FORMAT_INVALID_FILE_TYPE_SIGNATURE"), "JPA")); } archiveHeader.HeaderLength = ReadUShort(); archiveHeader.MajorVersion = ReadByte(); archiveHeader.MinorVersion = ReadByte(); archiveHeader.FileCount = ReadULong(); archiveHeader.UncompressedSize = ReadULong(); archiveHeader.CompressedSize = ReadULong(); if (archiveHeader.HeaderLength > 19) { // We need to loop while we have remaining header bytes ushort remainingBytes = (ushort)(archiveHeader.HeaderLength - 19); while (remainingBytes > 0) { // Do we have an extra header? The next three bytes must be JP followed by 0x01 and the header type byte[] headerSignature = ReadBytes(4); if ((headerSignature[0] != 0x4a) || (headerSignature[1] != 0x50) || (headerSignature[2] != 0x01)) { throw new InvalidArchiveException(Language.ResourceManager.GetString("ERR_FORMAT_INVALID_JPA_EXTRA_HEADER")); } // The next two bytes tell us how long this header is, without the 4 byte signature and type but WITH the header length field ushort extraHeaderLength = ReadUShort(); // Subtract the read bytes from the remaining bytes in the header. remainingBytes -= (ushort)(4 + extraHeaderLength); // Read the extra header switch (headerSignature[3]) { case 0x01: // Spanned Archive Marker header archiveHeader.TotalParts = ReadUShort(); break; default: // I have no idea what this is! throw new InvalidArchiveException(Language.ResourceManager.GetString("ERR_FORMAT_INVALID_JPA_EXTRA_HEADER")); } } } // Invoke the archiveInformation event. We need to do some work to get there, through... // -- Create a new archive information record ArchiveInformation info = new ArchiveInformation(); // -- Get the total archive size by looping all of its parts info.ArchiveSize = 0; for (int i = 1; i <= Parts; i++) { FileInfo fi = new FileInfo(ArchivePath); info.ArchiveSize += (ulong)fi.Length; } archiveHeader.TotalLength = info.ArchiveSize; // -- Incorporate bits from the file header info.FileCount = archiveHeader.FileCount; info.UncompressedSize = archiveHeader.UncompressedSize; info.CompressedSize = archiveHeader.CompressedSize; // -- Create the event arguments object ArchiveInformationEventArgs args = new ArchiveInformationEventArgs(info); // -- Finally, invoke the event OnArchiveInformationEvent(args); // Lastly, return the read archive header return(archiveHeader); }
public ArchiveInformationEventArgs(ArchiveInformation a) { ArchiveInformation = a; }
/// <summary> /// Reads the archive file's standard and end of archive headers and makes sure it's a valid JPS archive. /// </summary> /// <returns></returns> /// <exception cref="InvalidArchiveException"></exception> private JpsHeaderData ReadArchiveHeader() { // Open the first part Close(); Open(1); // Read the file signature. Must be "JPS" JpsHeaderData headerData; headerData.Signature = ReadAsciiString(3); if (headerData.Signature != "JPS") { throw new InvalidArchiveException( String.Format(Language.ResourceManager.GetString("ERR_FORMAT_INVALID_FILE_TYPE_SIGNATURE"), "JPS")); } // Read the rest of the header headerData.MajorVersion = ReadByte(); headerData.MinorVersion = ReadByte(); headerData.SpannedArchive = ReadByte(); headerData.ExtraHeaderLength = ReadUShort(); // Make sure it's a supported JPS version bool oneNine = (headerData.MajorVersion == 1) && (headerData.MinorVersion == 9); bool oneTen = (headerData.MajorVersion == 1) && (headerData.MinorVersion == 10); bool twoZero = (headerData.MajorVersion == 2) && (headerData.MinorVersion == 0); if (!oneNine && !oneTen && !twoZero) { throw new InvalidArchiveException(String.Format( Language.ResourceManager.GetString("ERR_FORMAT_JPS_INVALID_VERSION"), headerData.MajorVersion, headerData.MinorVersion )); } // Versions 1.9 and 1.10 must not have any extra header data. if ((oneNine || oneTen) && (headerData.ExtraHeaderLength > 0)) { throw new InvalidArchiveException(String.Format( Language.ResourceManager.GetString("ERR_FORMAT_JPS_INVALID_EXTRA_HEADER_FOR_VERSION"), headerData.MajorVersion, headerData.MinorVersion )); } // JPS 2.0 MUST have an extra header. Make sure it exists. if (twoZero && (headerData.ExtraHeaderLength != 76)) { throw new InvalidArchiveException(Language.ResourceManager.GetString("ERR_FORMAT_JPS_EXTRAHEADER_WRONGLENGTH")); } // Read the JPS 2.0 extra header if (twoZero) { ReadPbkdf2ExtraArchiveHeader(); } // In JPS 2.0 we are going to use PBKDF2 to derive the key from the password, therefore legacy needs to be // disabled. if (twoZero) { _useLegacyKey = false; } // Open the last part and read the End Of Archive header data Close(); Open(Parts); InputStream.Seek(-17, SeekOrigin.End); headerData.EndOfArchiveSignature = ReadAsciiString(3); if (headerData.EndOfArchiveSignature != "JPE") { throw new InvalidArchiveException( String.Format(Language.ResourceManager.GetString("ERR_FORMAT_INVALID_FILE_TYPE_SIGNATURE"), "JPS")); } // Read the rest of the end of archive header data headerData.NumberOfParts = ReadUShort(); headerData.NumberOfFiles = ReadULong(); headerData.UncompressedSize = ReadULong(); headerData.CompressedSize = ReadULong(); // Now we can reopen the first part and go past the header Open(1); SkipBytes(8 + headerData.ExtraHeaderLength); // Invoke the archiveInformation event. We need to do some work to get there, through... ArchiveInformation info = new ArchiveInformation(); info.ArchiveType = ArchiveType.Jps; // -- Get the total archive size by looping all of its parts info.ArchiveSize = 0; for (int i = 1; i <= Parts; i++) { FileInfo fi = new FileInfo(ArchivePath); info.ArchiveSize += (ulong)fi.Length; } headerData.TotalSize = info.ArchiveSize; // -- Incorporate bits from the file header info.CompressedSize = headerData.CompressedSize; info.UncompressedSize = headerData.UncompressedSize; info.FileCount = headerData.NumberOfFiles; // -- Create the event arguments object ArchiveInformationEventArgs args = new ArchiveInformationEventArgs(info); // -- Finally, invoke the event OnArchiveInformationEvent(args); return(headerData); }