예제 #1
0
        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();
            });
        }
예제 #2
0
        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);
            }
        }
예제 #3
0
        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);
        }
예제 #5
0
        /// <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);
        }
예제 #6
0
        /// <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;
 }
예제 #8
0
        /// <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);
        }