Exemplo n.º 1
0
        public void Load(string spcPath)
        {
            using BinaryReader reader = new BinaryReader(new FileStream(spcPath, FileMode.Open));

            // Verify the magic value, it could either be "CPS." (the one we want) or "$CFH" (most files in the console version, unusable for now)
            string magic = new ASCIIEncoding().GetString(reader.ReadBytes(4));

            if (magic == "$CFH")
            {
                // decompress using SRD method first, then resume
                return;
            }

            if (magic != "CPS.")
            {
                Console.WriteLine("ERROR: Not a valid SPC file, magic number invalid.");
                return;
            }

            // Read the first set of data
            Unknown1 = reader.ReadBytes(0x24);
            int fileCount = reader.ReadInt32();

            Unknown2 = reader.ReadInt32();
            reader.BaseStream.Seek(0x10, SeekOrigin.Current);

            // Verify file table header, should be "Root"
            if (!new ASCIIEncoding().GetString(reader.ReadBytes(4)).Equals("Root"))
            {
                Console.WriteLine("ERROR: Not a valid SPC file, table header invalid.");
                return;
            }
            reader.BaseStream.Seek(0x0C, SeekOrigin.Current);

            // For each subfile in the table, read the corresponding data
            for (int i = 0; i < fileCount; ++i)
            {
                SpcSubfile subfile = new SpcSubfile
                {
                    CompressionFlag = reader.ReadInt16(),
                    UnknownFlag     = reader.ReadInt16(),
                    CurrentSize     = reader.ReadInt32(),
                    OriginalSize    = reader.ReadInt32()
                };

                int nameLength = reader.ReadInt32();
                reader.BaseStream.Seek(0x10, SeekOrigin.Current);
                int namePadding = (0x10 - (nameLength + 1) % 0x10) % 0x10;
                subfile.Name = new ASCIIEncoding().GetString(reader.ReadBytes(nameLength));
                reader.BaseStream.Seek(namePadding + 1, SeekOrigin.Current);    // Discard the null terminator

                int dataPadding = (0x10 - subfile.CurrentSize % 0x10) % 0x10;
                subfile.Data = reader.ReadBytes(subfile.CurrentSize);
                reader.BaseStream.Seek(dataPadding, SeekOrigin.Current);

                Subfiles.Add(subfile);
            }
        }
Exemplo n.º 2
0
        /// <summary>
        /// Asynchronously inserts a file into the SPC archive. If a file with the same name already exists within the archive, it will be replaced.
        /// </summary>
        /// <param name="filename">The path of the file to be inserted into the SPC archive.</param>
        /// <param name="compress">Whether the subfile should be compressed before inserting. Unless you know what you're doing, leave this set to "true".</param>
        /// <param name="confirmation">An async delegate whose output will determine whether a file will be replaced. If null, there is no confirmation.</param>
        public async Task InsertSubfileAsync(string filename, bool compress = true, OverwriteConfirmationAsync confirmation = null)
        {
            FileInfo info = new FileInfo(filename);

            if (!info.Exists)
            {
                Console.WriteLine($"ERROR: Target file\"{info.FullName}\" does not exist.");
                return;
            }

            // Check if a subfile already exists with the specified name
            int existingIndex = -1;

            for (int s = 0; s < Subfiles.Count; ++s)
            {
                if (info.Name == Subfiles[s].Name)
                {
                    if (confirmation == null || await confirmation())
                    {
                        existingIndex = s;
                        break;
                    }
                }
            }

            using BinaryReader reader = new BinaryReader(new FileStream(filename, FileMode.Open));
            int        subfileSize     = (int)reader.BaseStream.Length;
            SpcSubfile subfileToInject = new SpcSubfile
            {
                CompressionFlag = 1,
                UnknownFlag     = (short)(subfileSize > ushort.MaxValue ? 8 : 4), // seems like this flag might relate to size? This is a BIG guess though.
                CurrentSize     = subfileSize,
                OriginalSize    = subfileSize,
                Name            = info.Name,
                Data            = reader.ReadBytes(subfileSize)
            };

            reader.Close();

            if (compress)
            {
                subfileToInject.Compress();
            }

            // Check if a subfile already exists with the specified name and replace
            if (existingIndex != -1)
            {
                Subfiles[existingIndex] = subfileToInject;
                return;
            }

            // We should only reach this code if there is not an existing subfile with the same name
            Subfiles.Add(subfileToInject);
        }