Пример #1
0
        public static EQArchive Load(string Filename, byte[] Contents)
        {
            if (Util.IsBlank(Filename) || (Contents == null))
            {
                // We got a bad filename, or the file is zero length, and thus not a PFS archive.

                return null;
            }

            Header _header = new Header();

            using (BinaryReader _input = new BinaryReader(new MemoryStream(Contents)))
            {
                try
                {
                    //
                    //   1. Read the file header
                    //

                    _header.IndexPointer = _input.ReadUInt32();
                    _header.MagicNumber = _input.ReadUInt32();
                    _header.VersionNumber = _input.ReadUInt32();
                }
                catch
                {
                    // Too small to be a PFS archive

                    return null;
                }

                if (_header.MagicNumber != _MagicNumber)
                {
                    // Not a PFS archive

                    return null;
                }

                EQArchive _archive = new EQArchive();
                _archive.Filename = Filename;
                _archive.SizeOnDisk = (UInt32)Contents.Length;

                try
                {
                    //
                    //   2. Read Index of File Pointers and Sizes in Archive
                    //

                    _input.BaseStream.Seek(_header.IndexPointer, SeekOrigin.Begin);

                    _header.EntryCount = _input.ReadUInt32();

                    if (_header.EntryCount == 0)
                    {
                        // Empty archive...?
                        _archive.Files = new SortedList<string, EQArchiveFile>();
                    }
                    else
                    {
                        _archive.Files = new SortedList<string, EQArchiveFile>((int)_header.EntryCount);
                    }

                    // Filename directory is the "file" at the end of the archive (with the highest FilePointer)
                    EQArchiveFile _directory = null;

                    // For verification later, which is optional, but will catch a malformed/corrupted archive.
                    Dictionary<UInt32, UInt32> _filenameCRCs = new Dictionary<UInt32, UInt32>();

                    // Files in a PFS archive tend to be stored by ascending order of FilenameCRC.
                    // However, the filename directory is sorted by FilePointer
                    SortedList<UInt32, EQArchiveFile> _files = new SortedList<UInt32, EQArchiveFile>();

                    for (UInt32 _index = 0; _index < _header.EntryCount; _index++)
                    {
                        EQArchiveFile _file = new EQArchiveFile();
                        UInt32 _filenameCRC = _input.ReadUInt32();
                        _file.FilePointer = _input.ReadUInt32();
                        _file.Size.Uncompressed = _input.ReadUInt32();
                        _filenameCRCs.Add(_file.FilePointer, _filenameCRC);

                        if ((_directory == null) || (_file.FilePointer > _directory.FilePointer))
                        {
                            _directory = _file;
                        }

                        _files.Add(_file.FilePointer, _file);
                    }

                    if ((_input.BaseStream.Length - _input.BaseStream.Position) >= 9)
                    {
                        // PFS Footer

                        char[] _token = _input.ReadChars(5);

                        if (new String(_token).Equals("STEVE"))
                        {
                            // Valid Footer Token

                            _header.DateStamp = _input.ReadUInt32();
                        }
                    }

                    //
                    //   3. Read the compressed file entries (each split into compressed chunks)
                    //

                    foreach (EQArchiveFile _file in _files.Values)
                    {
                        // Seek to entry position in stream
                        _input.BaseStream.Seek(_file.FilePointer, SeekOrigin.Begin);

                        UInt32 _totalUncompressedBytes = _file.Size.Uncompressed;
                        _file.Size.Uncompressed = 0;

                        while ((_file.Size.Uncompressed < _totalUncompressedBytes) && (_input.BaseStream.Position < _input.BaseStream.Length))
                        {
                            UInt32 _blockSizeCmp = _input.ReadUInt32();
                            UInt32 _blockSizeUnc = _input.ReadUInt32();

                            // Sanity Check 1: Uncompressed data larger than what we were told?
                            if ((_blockSizeUnc + _file.Size.Uncompressed) > _totalUncompressedBytes)
                            {
                                throw new Exception();
                            }

                            // Sanity Check 2: Compressed data goes past the end of the file?
                            if ((_input.BaseStream.Position + _blockSizeCmp) > _input.BaseStream.Length)
                            {
                                throw new Exception();
                            }

                            _file.AddChunk(new EQArchiveFile.Chunk(Contents, (UInt32)_input.BaseStream.Position, _blockSizeCmp, _blockSizeUnc, true));

                            _input.BaseStream.Position += _blockSizeCmp;
                        }
                    }

                    //
                    //    4. Unpack and parse the directory of filenames from the "file" at the end of the archive (highest FilePointer)
                    //

                    // Remove directory from file entries in archive. We'll have to rebuild it when saving the archive anyway.
                    _files.Remove(_directory.FilePointer);
                    _header.EntryCount--;

                    // Load filenames from directory
                    BinaryReader _dirStream = new BinaryReader(new MemoryStream(_directory.GetContents()));

                    UInt32 _filenameCount = _dirStream.ReadUInt32();

                    if (_filenameCount > _header.EntryCount)
                    {
                        // If we somehow have more filenames than entries in the archive, ignore the glitched extras

                        _filenameCount = _header.EntryCount;
                    }

                    _archive.Files = new SortedList<string, EQArchiveFile>();

                    foreach (EQArchiveFile _file in _files.Values)
                    {
                        Int32 _len = _dirStream.ReadInt32();
                        char[] _inputname = _dirStream.ReadChars(_len);
                        UInt32 _crc = GetFilenameCRC(_inputname);

                        if (_crc != _filenameCRCs[_file.FilePointer])
                        {
                            // Filename doesn't match with what we were given in Step 2

                            // This happens in gequip.s3d. We are ignoring it.

                            //throw new Exception();
                        }

                        _file.Filename = new string(_inputname, 0, _len - 1);

                        _archive.Files.Add(_file.Filename.ToLower(), _file);
                    }

                    // All entries loaded and filenames read from directory.

                    _archive.Status = Result.OK;
                }
                catch
                {
                    _archive.Status = Result.MalformedFile;
                }

                return _archive;
            }
        }
Пример #2
0
        private void AddToMRUs(EQArchive OldArchive)
        {
            if ((Settings.RememberMRUs > 0) && (OldArchive != null) && (OldArchive.Filename != "(Untitled)") && (OldArchive.FilePath != ""))
            {
                string _fullPath = OldArchive.FilePath + @"\" + OldArchive.Filename;

                int _maxMRU = (Settings.RememberMRUs - 1);
                int _newMRU = _maxMRU;

                for (int _mru = 0; _mru < _maxMRU; _mru++)
                {
                    if (Settings.MRUs[_mru].Equals(_fullPath, StringComparison.CurrentCultureIgnoreCase))
                    {
                        _newMRU = _mru;

                        break;
                    }
                }

                for (int _i = _newMRU; _i > 0; _i--)
                {
                    Settings.MRUs[_i] = Settings.MRUs[_i - 1];
                }

                Settings.MRUs[0] = _fullPath;
            }
        }
Пример #3
0
        public void Status_Changed(bool ForceListReload)
        {
            if (ArchiveLoading && (NewFile != null))
            {
                ListViewItem _item = new ListViewItem();

                _item.Tag = NewFile;
                UpdateItem(_item, false);

                listView1.Items.Add(_item);

                Application.DoEvents();
            }
            else
            {
                saveToolStripMenuItem.Enabled = ((CurrentArchive != null) && (CurrentArchive.IsDirty) && (!CurrentArchive.Filename.Equals("(Untitled)")));
                saveToolStripButton.Enabled = saveToolStripMenuItem.Enabled;
                saveAsToolStripMenuItem.Enabled = (CurrentArchive != null);
                saveAsToolStripButton.Enabled = saveAsToolStripMenuItem.Enabled;
                importFileToolStripMenuItem.Enabled = (CurrentArchive != null);
                importFileToolStripButton.Enabled = importFileToolStripMenuItem.Enabled;

                if (ForceListReload || (LastArchive != CurrentArchive) || ArchiveChanged)
                {
                    ViewMode_Changed();

                    CancelThumbnailThread();

                    listView1.Items.Clear();

                    while (itemThumbsLarge.Images.Count > 3)
                    {
                        // Clear all but our default built-in icons

                        itemThumbsLarge.Images.RemoveAt(3);
                        itemThumbsSmall.Images.RemoveAt(3);
                    }

                    if (CurrentArchive != null)
                    {
                        foreach (EQArchiveFile _file in CurrentArchive.Files.Values)
                        {
                            ListViewItem _item = new ListViewItem();

                            _item.Tag = _file;
                            UpdateItem(_item, false);

                            listView1.Items.Add(_item);
                        }
                    }

                    listView1.Enabled = (CurrentArchive != null);

                    UpdateMRUs();

                    LastArchive = CurrentArchive;
                    ArchiveChanged = false;
                    listView1.LabelEdit = false;

                    if (CurrentArchive != null)
                    {
                        toolStripProgressBar1.Value = 0;
                        toolStripProgressBar1.Maximum = CurrentArchive.Files.Count;
                        ThumbnailsLoaded = false;
                        toolStripProgressBar1.Visible = true;
                    }

                    Application.DoEvents();

                    ViewMode_Restore();

                    threadListView.RunWorkerAsync();
                }
            }

            if (CurrentArchive == null)
            {
                this.Text = Application.ProductName + " " + VersionNumber;
                toolStripStatusLabelFileCount.Text = ""; // "Files: 0";
                toolStripStatusLabelArchiveSize.Text = ""; // "Size on Disk: 0";
            }
            else
            {
                this.Text = CurrentArchive.Filename + (CurrentArchive.IsDirty ? "* - " : " - ") + Application.ProductName + " " + VersionNumber;
                toolStripStatusLabelFileCount.Text = "Files: " + CurrentArchive.Files.Count;
                toolStripStatusLabelArchiveSize.Text = "Size on Disk: " + CurrentArchive.SizeOnDisk.ToString("###,###,###,##0");
            }

            Selection_Changed();
        }
Пример #4
0
        public void LoadArchive(string FilePath)
        {
            if (!ConfirmDiscard())
            {
                // User canceled the change in archive

                return;
            }

            CancelThumbnailThread();

            EQArchive _newArchive;

            if (FilePath == null)
            {
                _newArchive = null;
            }
            else if (FilePath == "")
            {
                // Requesting a new empty archive

                _newArchive = new EQArchive();
            }
            else
            {
                _newArchive = EQArchive.Load(FilePath);

                switch (_newArchive.Status)
                {
                    case Result.OK:
                        // Hey, look at that. Nothing bad happened. Awesome. Let's use it.
                        break;
                    case Result.WrongFileType:
                        MessageBox.Show(this, "The specified file was not recognized as a supported EQ Archive type:\r\n\r\n" + FilePath, "Problem Opening Archive", MessageBoxButtons.OK, MessageBoxIcon.Error);
                        return;
                    case Result.MalformedFile:
                        MessageBox.Show(this, "The specified file was recognized as an EQ archive, but contained invalid data:\r\n\r\n" + FilePath, "Problem Opening Archive", MessageBoxButtons.OK, MessageBoxIcon.Error);
                        return;
                    case Result.FileTooLarge:
                        MessageBox.Show(this, "The specified file is larger than the 4GB limit supported (WTF?!):\r\n\r\n" + FilePath, "Problem Opening Archive", MessageBoxButtons.OK, MessageBoxIcon.Error);
                        return;
                    case Result.FileReadError:
                        MessageBox.Show(this, "The specified file could not be read, or may be corrupted:\r\n\r\n" + FilePath, "Problem Opening Archive", MessageBoxButtons.OK, MessageBoxIcon.Error);
                        return;
                    case Result.FileNotFound:
                        MessageBox.Show(this, "The specified file does not exist:\r\n\r\n" + FilePath, "Problem Opening Archive", MessageBoxButtons.OK, MessageBoxIcon.Error);
                        return;
                    case Result.DirectoryNotFound:
                        MessageBox.Show(this, "The specified file location not exist:\r\n\r\n" + FilePath, "Problem Opening Archive", MessageBoxButtons.OK, MessageBoxIcon.Error);
                        return;
                    default:
                        MessageBox.Show(this, "The specified file could not be opened as an archive:\n\n" + FilePath + "\n\nThe error received was: " + _newArchive.Status.ToString(), "Problem Opening Archive", MessageBoxButtons.OK, MessageBoxIcon.Error);
                        return;
                }
            }

            AddToMRUs(CurrentArchive);

            CurrentArchive = _newArchive;
            ArchiveChanged = true;

            Status_Changed();
            UpdateMRUs();
        }
Пример #5
0
        private bool ImportFile(EQArchiveFile File, bool Override)
        {
            if (CurrentArchive == null)
            {
                CurrentArchive = new EQArchive();
            }

            EQArchiveFile _existing;

            if (Settings.ImportFormat != "")
            {
                _existing = CurrentArchive.FindFileOrSimilarImage(File.Filename);
            }
            else
            {
                _existing = CurrentArchive.FindFile(File.Filename);
            }

            string _newName = null;

            if (_existing != null)
            {
                _newName = _existing.Filename;

                if (!Override || Settings.ConfirmImportOverwrite)
                {
                    switch (MessageBox.Show(this, "The file " + _existing.Filename + " exists in the archive.\n\nDo you wish to overwrite this file with your new one?", "Importing File Exists", MessageBoxButtons.YesNo, MessageBoxIcon.Question))
                    {
                        case DialogResult.No:
                            _newName = File.Filename;

                            while (CurrentArchive.FindFileOrSimilarImage(_newName) != null)
                            {
                                _newName = System.IO.Path.GetFileNameWithoutExtension(_newName) + " (New)" + System.IO.Path.GetExtension(_newName);
                            }
                            break;
                    }
                }

                File.Filename = _newName;

                if (_newName == _existing.Filename) // We're replacing it.
                {
                    DeleteItem(listView1.Items[_existing.Filename.ToLower()]);
                }
            }

            if ((Settings.ImportFormat != "") && (File.GetImage() != null) && (File.ImageFormat != Settings.ImportFormat))
            {
                File = File.AsFormat(Settings.ImportFormat, (_existing == null));
            }

            bool _ok = (CurrentArchive.Add(File) == Result.OK);

            NewFile = File;
            Status_Changed(true);

            return _ok;
        }
Пример #6
0
        public static EQArchive Load(string Filename, byte[] Contents)
        {
            if (Util.IsBlank(Filename) || (Contents == null))
            {
                // We got a bad filename, or the file is zero length, and thus not a PFS archive.

                return(null);
            }

            Header _header = new Header();

            using (BinaryReader _input = new BinaryReader(new MemoryStream(Contents)))
            {
                try
                {
                    //
                    //   1. Read the file header
                    //

                    _header.IndexPointer  = _input.ReadUInt32();
                    _header.MagicNumber   = _input.ReadUInt32();
                    _header.VersionNumber = _input.ReadUInt32();
                }
                catch
                {
                    // Too small to be a PFS archive

                    return(null);
                }

                if (_header.MagicNumber != _MagicNumber)
                {
                    // Not a PFS archive

                    return(null);
                }

                EQArchive _archive = new EQArchive();
                _archive.Filename   = Filename;
                _archive.SizeOnDisk = (UInt32)Contents.Length;

                try
                {
                    //
                    //   2. Read Index of File Pointers and Sizes in Archive
                    //

                    _input.BaseStream.Seek(_header.IndexPointer, SeekOrigin.Begin);

                    _header.EntryCount = _input.ReadUInt32();

                    if (_header.EntryCount == 0)
                    {
                        // Empty archive...?
                        _archive.Files = new SortedList <string, EQArchiveFile>();
                    }
                    else
                    {
                        _archive.Files = new SortedList <string, EQArchiveFile>((int)_header.EntryCount);
                    }

                    // Filename directory is the "file" at the end of the archive (with the highest FilePointer)
                    EQArchiveFile _directory = null;

                    // For verification later, which is optional, but will catch a malformed/corrupted archive.
                    Dictionary <UInt32, UInt32> _filenameCRCs = new Dictionary <UInt32, UInt32>();

                    // Files in a PFS archive tend to be stored by ascending order of FilenameCRC.
                    // However, the filename directory is sorted by FilePointer
                    SortedList <UInt32, EQArchiveFile> _files = new SortedList <UInt32, EQArchiveFile>();

                    for (UInt32 _index = 0; _index < _header.EntryCount; _index++)
                    {
                        EQArchiveFile _file        = new EQArchiveFile();
                        UInt32        _filenameCRC = _input.ReadUInt32();
                        _file.FilePointer       = _input.ReadUInt32();
                        _file.Size.Uncompressed = _input.ReadUInt32();
                        _filenameCRCs.Add(_file.FilePointer, _filenameCRC);

                        if ((_directory == null) || (_file.FilePointer > _directory.FilePointer))
                        {
                            _directory = _file;
                        }

                        _files.Add(_file.FilePointer, _file);
                    }

                    if ((_input.BaseStream.Length - _input.BaseStream.Position) >= 9)
                    {
                        // PFS Footer

                        char[] _token = _input.ReadChars(5);

                        if (new String(_token).Equals("STEVE"))
                        {
                            // Valid Footer Token

                            _header.DateStamp = _input.ReadUInt32();
                        }
                    }

                    //
                    //   3. Read the compressed file entries (each split into compressed chunks)
                    //

                    foreach (EQArchiveFile _file in _files.Values)
                    {
                        // Seek to entry position in stream
                        _input.BaseStream.Seek(_file.FilePointer, SeekOrigin.Begin);

                        UInt32 _totalUncompressedBytes = _file.Size.Uncompressed;
                        _file.Size.Uncompressed = 0;

                        while ((_file.Size.Uncompressed < _totalUncompressedBytes) && (_input.BaseStream.Position < _input.BaseStream.Length))
                        {
                            UInt32 _blockSizeCmp = _input.ReadUInt32();
                            UInt32 _blockSizeUnc = _input.ReadUInt32();

                            // Sanity Check 1: Uncompressed data larger than what we were told?
                            if ((_blockSizeUnc + _file.Size.Uncompressed) > _totalUncompressedBytes)
                            {
                                throw new Exception();
                            }

                            // Sanity Check 2: Compressed data goes past the end of the file?
                            if ((_input.BaseStream.Position + _blockSizeCmp) > _input.BaseStream.Length)
                            {
                                throw new Exception();
                            }

                            _file.AddChunk(new EQArchiveFile.Chunk(Contents, (UInt32)_input.BaseStream.Position, _blockSizeCmp, _blockSizeUnc, true));

                            _input.BaseStream.Position += _blockSizeCmp;
                        }
                    }

                    //
                    //    4. Unpack and parse the directory of filenames from the "file" at the end of the archive (highest FilePointer)
                    //

                    // Remove directory from file entries in archive. We'll have to rebuild it when saving the archive anyway.
                    _files.Remove(_directory.FilePointer);
                    _header.EntryCount--;

                    // Load filenames from directory
                    BinaryReader _dirStream = new BinaryReader(new MemoryStream(_directory.GetContents()));

                    UInt32 _filenameCount = _dirStream.ReadUInt32();

                    if (_filenameCount > _header.EntryCount)
                    {
                        // If we somehow have more filenames than entries in the archive, ignore the glitched extras

                        _filenameCount = _header.EntryCount;
                    }

                    _archive.Files = new SortedList <string, EQArchiveFile>();

                    foreach (EQArchiveFile _file in _files.Values)
                    {
                        Int32  _len       = _dirStream.ReadInt32();
                        char[] _inputname = _dirStream.ReadChars(_len);
                        UInt32 _crc       = GetFilenameCRC(_inputname);

                        if (_crc != _filenameCRCs[_file.FilePointer])
                        {
                            // Filename doesn't match with what we were given in Step 2

                            // This happens in gequip.s3d. We are ignoring it.

                            //throw new Exception();
                        }

                        _file.Filename = new string(_inputname, 0, _len - 1);

                        _archive.Files.Add(_file.Filename.ToLower(), _file);
                    }

                    // All entries loaded and filenames read from directory.

                    _archive.Status = Result.OK;
                }
                catch
                {
                    _archive.Status = Result.MalformedFile;
                }

                return(_archive);
            }
        }