Example #1
0
        /// <summary>
        /// Gets the next block.
        /// </summary>
        /// <returns></returns>
        /// <exception cref="PK2NotLoadedException"></exception>
        public PK2Block GetNextBlock()
        {
            if (FileAdapter.GetInstance() == null)
            {
                throw new PK2NotLoadedException();
            }

            return(HasBlocks ? new PK2Block(FileAdapter.GetInstance().ReadData((long)Entries[19].NextChain, 2560), Entries[19].NextChain) : this);
        }
Example #2
0
        /// <summary>
        /// Saves the block back to the PK2 archive.
        /// </summary>
        /// <exception cref="PK2NotLoadedException"></exception>
        public void Save()
        {
            if (FileAdapter.GetInstance() == null)
            {
                throw new PK2NotLoadedException();
            }

            FileAdapter.GetInstance().WriteData(ToByteArray(), (long)Offset);
        }
Example #3
0
        /// <summary>
        /// Gets the data.
        /// </summary>
        /// <returns></returns>
        /// <exception cref="PK2NotLoadedException"></exception>
        /// <exception cref="System.InvalidOperationException">It's impossible to read data from a directory or from a deleted file.</exception>
        public byte[] GetData()
        {
            if (FileAdapter.GetInstance() == null)
            {
                throw new PK2NotLoadedException();
            }

            if (Type != PK2EntryType.File)
            {
                throw new InvalidOperationException("It's impossible to read data from a directory or from a deleted file."); //TODO: find something better
            }
            return(FileAdapter.GetInstance().ReadData((long)Position, (int)Size));
        }
Example #4
0
        /// <summary>
        /// Extracts the file to the specified destination
        /// </summary>
        /// <param name="destination">The destination.</param>
        /// <exception cref="PK2NotLoadedException"></exception>
        /// <exception cref="System.InvalidOperationException">Directories can not be extracted.</exception>
        public void Extract(string destination)
        {
            if (FileAdapter.GetInstance() == null)
            {
                throw new PK2NotLoadedException();
            }

            if (Type != PK2EntryType.File)
            {
                throw new InvalidOperationException("Directories can not be extracted."); //TODO: find something better
            }
            File.WriteAllBytes(destination, FileAdapter.GetInstance().ReadData((long)Position, (int)Size));
        }
Example #5
0
        /// <summary>
        /// Reads the block.
        /// </summary>
        /// <param name="position">The position.</param>
        /// <param name="currentDirectory">The current directory.</param>
        private void ReadBlockAt(ulong position, PK2Directory currentDirectory = null)
        {
            var currentBlockBuffer = FileAdapter.GetInstance().ReadData((long)position, 2560);
            var currentBlock       = new PK2Block(currentBlockBuffer, position);

            //Check if the chain continues at another position
            if (currentBlock.Entries[19].NextChain > 0)
            {
                ReadBlockAt(currentBlock.Entries[19].NextChain);
            }

            //Read the subfolder chain
            //The folder "." and ".." are required if you which to use "free-browsing" mode, without reading the whole index at once
            foreach (var pk2Entry in currentBlock.Entries.Where(entry => !entry.Name.StartsWith(".") && entry.Position > 0))
            {
                switch (pk2Entry.Type)
                {
                case PK2EntryType.Directory:
                    if (Config.Mode == PK2Mode.Index)
                    {
                        var subDirectory = new PK2Directory(pk2Entry, currentDirectory?.Path);
                        _directories.Add(subDirectory);
                        ReadBlockAt(pk2Entry.Position, subDirectory);
                    }
                    else
                    {
                        ReadBlockAt(pk2Entry.Position);
                    }

                    break;

                case PK2EntryType.File:
                    if (Config.Mode == PK2Mode.Index)
                    {
                        _files.Add(new PK2File(pk2Entry, currentDirectory?.Path));
                    }
                    break;
                }
            }

            if (Config.Mode == PK2Mode.IndexBlocks)
            {
                Blocks.Add(currentBlock);
            }
        }
Example #6
0
        /// <summary>
        /// Creates a new block within the PK2.
        /// </summary>
        /// <param name="entries">The entries.</param>
        /// <returns></returns>
        /// <exception cref="PK2NotLoadedException"></exception>
        public static PK2Block Create(PK2Entry[] entries = null)
        {
            if (FileAdapter.GetInstance() == null)
            {
                throw new PK2NotLoadedException();
            }

            var buffer = new byte[2560];

            using (var stream = new StreamWorker(buffer, StreamOperation.Write))
            {
                for (var i = 0; i < 20; i++)
                {
                    stream.WriteByteArray(entries?[i] != null ? entries[i].ToByteArray() : new PK2Entry().ToByteArray());
                }
            }

            return(new PK2Block(buffer, (ulong)FileAdapter.GetInstance().AppendData(buffer)));
        }
Example #7
0
        /// <summary>
        /// Reads the block at.
        /// This function does not recursively ready any "sub-chunks"
        /// </summary>
        /// <param name="position">The position.</param>
        /// <returns></returns>
        private void ReadBlockAt(ulong position)
        {
            Blocks      = new PK2BlockCollection();
            Directories = new List <PK2Directory>();
            Files       = new List <PK2File>();

            while (true)
            {
                try
                {
                    var currentBlockBuffer = FileAdapter.GetInstance().ReadData((long)position, 2560);
                    var currentBlock       = new PK2Block(currentBlockBuffer, position);

                    Blocks.Blocks.Add(currentBlock);

                    foreach (var entry in currentBlock.Entries)
                    {
                        switch (entry.Type)
                        {
                        case PK2EntryType.Directory:
                            Directories.Add(new PK2Directory(entry, ""));
                            break;

                        case PK2EntryType.File:
                            Files.Add(new PK2File(entry, ""));
                            break;
                        }
                    }

                    //read the next block (only if the first block was not enough for the folder)
                    if (currentBlock.Entries[19].NextChain > 0)
                    {
                        position = currentBlock.Entries[19].NextChain;
                        continue;
                    }

                    break;
                }
                catch { throw new InvalidBlockException((long)position); } //should only be thrown, if the user fakes any position data in any entry!
            }
        }
Example #8
0
        /// <summary>
        /// Creates the file.
        /// </summary>
        /// <param name="type">The type.</param>
        /// <param name="parent">The parent.</param>
        /// <param name="name">The name.</param>
        /// <param name="data">The data. Obsolete if the type is a directory.</param>
        /// <returns></returns>
        /// <exception cref="System.InvalidOperationException">Can only create new items in a directory!</exception>
        /// <exception cref="PK2NotLoadedException"></exception>
        /// <exception cref="System.NullReferenceException">Can not write to an empty block</exception>
        public static PK2Entry Create(PK2EntryType type, PK2Entry parent, string name, byte[] data = null)
        {
            if (parent.Type != PK2EntryType.Directory)
            {
                throw new InvalidOperationException("Can only create new items in a directory!");
            }

            if (FileAdapter.GetInstance() == null)
            {
                throw new PK2NotLoadedException();
            }

            if (parent.GetChildBlock() == null)
            {
                throw new NullReferenceException("Can not write to an empty block");
            }

            var entryToOverwrite = parent.GetChildBlock().GetFirstEmptyEntry();

            //If all blocks are ocupied we have to create a new one
            if (entryToOverwrite == null)
            {
                var newBlock = PK2Block.Create();

                //Tell the last entry where to find our new block..
                var lastEntry = parent.GetChildBlock().GetLastBlock().Entries[19];
                lastEntry.NextChain = newBlock.Offset;
                lastEntry.Save();

                entryToOverwrite = newBlock.GetFirstEmptyEntry();
            }

            if (type == PK2EntryType.Directory && name == "." || name == "..")
            {
                entryToOverwrite.Position = name == "." ? entryToOverwrite.Block.Offset : parent.Block.Offset;
            }

            //create new block for the sub directories
            if (type == PK2EntryType.Directory && name != "." && name != "..")
            {
                var newBlock = PK2Block.Create();
                entryToOverwrite.Position = newBlock.Offset;
            }

            //Assign properties to the entry
            entryToOverwrite.Type       = type;
            entryToOverwrite.AccessTime = DateTime.Now;
            entryToOverwrite.CreateTime = DateTime.Now;
            entryToOverwrite.ModifyTime = DateTime.Now;
            entryToOverwrite.Name       = name;

            if (type == PK2EntryType.File && data != null)
            {
                entryToOverwrite.Size = (uint)data.Length;
            }

            //Write file to PK2 and assign the position
            if (type == PK2EntryType.File)
            {
                entryToOverwrite.Position = (ulong)FileAdapter.GetInstance().AppendData(data);
            }

            //Write the entry to the PK2
            entryToOverwrite.Save();

            if (type != PK2EntryType.Directory || name == "." || name == "..")
            {
                return(entryToOverwrite);
            }

            //Create those browser things...
            Create(PK2EntryType.Directory, entryToOverwrite, ".");
            Create(PK2EntryType.Directory, entryToOverwrite, "..");

            return(entryToOverwrite);
        }
Example #9
0
 /// <summary>
 /// Gets the child block if the entry is a directory.
 /// </summary>
 /// <returns></returns>
 public PK2Block GetChildBlock()
 {
     return(new PK2Block(FileAdapter.GetInstance().ReadData((long)Position, 2560), Position));
 }
Example #10
0
        /// <summary>
        /// Initializes a new instance of the <see cref="PK2Archive"/> class.
        /// The key is set to the isro standard encryption key.
        /// Do not provide any baseKey, if you wish to use the default base key for the archive.
        /// </summary>
        /// <exception cref="System.IO.FileNotFoundException"></exception>
        /// <exception cref="SlimPK2.Security.BlowfishSecurityException"></exception>
        /// <exception cref="SlimPK2.Types.InvalidHeaderException"></exception>
        public PK2Archive(string path, PK2Config config = null)
        {
            if (!File.Exists(path))
            {
                throw new FileNotFoundException(path);
            }

            //Initialize default config
            if (config == null)
            {
                config = PK2Config.GetDefault();
            }

            //assign the config to this instance
            Config = config;

            //Create file reader...
            FileAdapter.SetInstance(new FileAdapter(path));
            Path = path;

            //Read header...
            Header = new PK2Header(FileAdapter.GetInstance().ReadData(0, 256));

            if (Header.Encrypted)
            {
                var blowfishKey = BlowfishUtilities.GenerateFinalBlowfishKey(Config.Key, Config.BaseKey);
                var blowfish    = new Blowfish();
                blowfish.Initialize(blowfishKey);
                BlowfishUtilities.SetBlowfish(blowfish);

                var tempChecksum =
                    BlowfishUtilities.GetBlowfish().Encode(Encoding.ASCII.GetBytes("Joymax Pak File"));

                //Check if the security checksum equals the generated checksum
                if (tempChecksum[0] != Header.SecurityChecksum[0] ||
                    tempChecksum[1] != Header.SecurityChecksum[1] ||
                    tempChecksum[2] != Header.SecurityChecksum[2])
                {
                    throw new BlowfishSecurityException(Config.Key);
                }
            }

            if (Config.Mode != PK2Mode.FreeBrowse)
            {
                switch (Config.Mode)
                {
                case PK2Mode.IndexBlocks:
                    Blocks = new List <PK2Block>();
                    ReadBlockAt(256);
                    break;

                case PK2Mode.Index:
                    _files       = new List <PK2File>();
                    _directories = new List <PK2Directory>();

                    ReadBlockAt(256, new PK2Directory());
                    break;
                }
            }
            else
            {
                _navigator = new PK2Navigator();
            }

            Loaded = true;
        }