Esempio n. 1
0
        /// <summary>
        /// Extract a file to byte array using the path
        /// </summary>
        /// <param name="fullPath">Internal full path for the file to extract</param>
        /// <returns>Uncompressed data and no error string on success, null data and an error string otherwise</returns>
        public (byte[] data, string err) Extract(string fullPath)
        {
            // If the file isn't in the archive, we can't extract it
            if (!Exists(fullPath))
            {
                return(null, $"Path '{fullPath}' does not exist in the archive");
            }

            // Get a local reference to the file we care about
            CompressedFile file = Files[fullPath];

            // Attempt to read the compressed data
            inputStream.Seek(DataStart + file.Offset, SeekOrigin.Begin);
            byte[] compressedData = new byte[file.CompressedSize];
            int    read           = inputStream.Read(compressedData, 0, (int)file.CompressedSize);

            if (read != (int)file.CompressedSize)
            {
                return(null, "Could not read all required data");
            }

            // Decompress the data
            List <byte> output = new List <byte>();
            int         ret    = BlastDecoder.Blast(compressedData, output);

            if (ret != 0)
            {
                return(null, $"Blast error: {ret}");
            }

            // Return the decompressed data
            return(output.ToArray(), null);
        }
Esempio n. 2
0
        /// <summary>
        /// Load the file set as the current path
        /// </summary>
        /// <returns>Success and error strings, if applicable</returns>
        private (bool success, string err) LoadFile()
        {
            // If the file doesn't exist, we can't do anything
            if (!File.Exists(FilePath))
            {
                return(false, $"File '{FilePath}' does not exist");
            }

            // Attempt to open the file for reading
            try
            {
                inputStream = File.OpenRead(FilePath);
            }
            catch
            {
                return(false, "Cannot open file");
            }

            // Create the header from the input file
            Header = Header.Create(inputStream);
            if (Header == null)
            {
                return(false, "Header could not be read");
            }

            // Validate the file signature
            if (Header.Signature != 0x8C655D13)
            {
                return(false, "Invalid signature");
            }

            // Validate the TOC
            long fileSize = inputStream.Length;

            if (Header.TocAddress >= fileSize)
            {
                return(false, $"Invalid TOC address: {Header.TocAddress}");
            }

            // Move to the TOC
            inputStream.Seek(Header.TocAddress, SeekOrigin.Begin);

            // Read all directory info
            for (int i = 0; i < Header.DirCount; i++)
            {
                ushort fileCount = inputStream.ReadUInt16();
                ushort chunkSize = inputStream.ReadUInt16();
                string name      = inputStream.ReadUInt16HeaderedString();

                inputStream.Seek(chunkSize - name.Length - 6, SeekOrigin.Current);
                Directories.Add(new ArchiveDirectory {
                    Name = name, FileCount = fileCount
                });
            }

            // For each directory, read all file info
            uint accumOffset = 0;

            foreach (ArchiveDirectory directory in Directories)
            {
                for (int i = 0; i < directory.FileCount; i++)
                {
                    // Read in the file information
                    inputStream.Seek(7, SeekOrigin.Current);                    // 00-06
                    uint compressedSize = inputStream.ReadUInt32();             // 07-10
                    inputStream.Seek(12, SeekOrigin.Current);                   // 11-22
                    ushort chunkSize = inputStream.ReadUInt16();                // 23-24
                    inputStream.Seek(4, SeekOrigin.Current);                    // 25-28
                    string filename = inputStream.ReadUInt8HeaderedString();    // 29-XX
                    inputStream.Seek(chunkSize - filename.Length - 30, SeekOrigin.Current);

                    // Determine the full path of the internal file
                    string fullpath;
                    if (!string.IsNullOrWhiteSpace(directory.Name) && directory.Name.Length > 0)
                    {
                        fullpath = Path.Combine(directory.Name, filename);
                    }
                    else
                    {
                        fullpath = filename;
                    }

                    // Add the file to the list
                    Files[fullpath] = new CompressedFile
                    {
                        Name           = filename,
                        FullPath       = fullpath,
                        CompressedSize = compressedSize,
                        Offset         = accumOffset,
                    };

                    // Accumulate the new offset
                    accumOffset += compressedSize;
                }
            }

            return(true, null);
        }