Exemplo n.º 1
0
        /// <summary>
        /// Parses a Sonic Heroes ONE file from a byte array and returns a ONE file structure back.
        /// </summary>
        /// <returns>The structure of a ONE Archive.</returns>
        // ReSharper disable once InconsistentNaming
        public static ONEArchive ParseONEFile(ref byte[] file)
        {
            ONEArchive oneArchive = new ONEArchive();

            // Stores a pointer, increasing as we read the individual file structures.
            int pointer = 0;

            // Parse the header and individual sections.
            oneArchive.FileHeader            = StructUtilities.ArrayToStructureUnsafe <ONEHeader>(ref file, pointer, ref pointer);
            oneArchive.FileNameSectionHeader = StructUtilities.ArrayToStructureUnsafe <ONEFileNameSectionHeader>(ref file, pointer, ref pointer);

            // Parse all of the filenames.
            int fileNameCount = oneArchive.FileNameSectionHeader.GetNameCount();

            oneArchive.FileNames = new ONEFileName[fileNameCount];

            for (int x = 0; x < fileNameCount; x++)
            {
                oneArchive.FileNames[x] = StructUtilities.ArrayToStructureUnsafe <ONEFileName>(ref file, pointer, ref pointer);
            }

            // Parse all of the files.
            oneArchive.Files = new List <ONEFile>(fileNameCount);
            int fileCount = oneArchive.FileNames.Count(x => x.ToString() != "");

            // Some ONE files have been padded at the end of file, thus reading until the end of file may fail - only take as many files as we have filenames.
            while ((pointer < file.Length) && (oneArchive.Files.Count < fileCount))
            {
                // Create ONE ArchiveFile
                ONEFile oneFile = new ONEFile();

                // Parse the header.
                oneFile.ONEFileHeader = StructUtilities.ArrayToStructureUnsafe <ONEFileHeader>(ref file, pointer, ref pointer);

                // Now parse the data.
                oneFile.CompressedData = new byte[oneFile.ONEFileHeader.FileSize];
                Array.Copy(file, pointer, oneFile.CompressedData, 0, oneFile.CompressedData.Length);
                pointer += oneFile.CompressedData.Length;

                oneArchive.Files.Add(oneFile);
            }

            return(oneArchive);
        }
Exemplo n.º 2
0
        /// <summary>
        /// Generates a Heroes ONE archive from the provided HeroesONE Archive structure.
        /// </summary>
        public List <byte> BuildHeroesONEArchive()
        {
            // Note: The file name section has 2 blank entries at file name index 0 and 1, we need to skip those.
            // Populate some data before we write it.
            ONEHeader fileHeader = new ONEHeader();
            ONEFileNameSectionHeader fileNameSectionHeader = new ONEFileNameSectionHeader();

            // Header
            fileHeader.RenderWareVersion = RwVersion;
            fileHeader.FileSize          = 0;
            fileHeader.Null = 0;

            // Name Header
            fileNameSectionHeader.RenderWareVersion     = RwVersion;
            fileNameSectionHeader.Unknown               = 1;
            fileNameSectionHeader.FileNameSectionLength = ((Files.Count + 2) * ONEFileName.FileNameLength);

            // Populate ArchiveFile names
            List <ONEFileName> fileNames = new List <ONEFileName>(ONEArchive.MAX_FILE_COUNT);

            // Insert blank entries
            fileNames.Add(new ONEFileName(""));
            fileNames.Add(new ONEFileName(""));

            for (int x = 0; x < Files.Count; x++)
            {
                fileNames.Add(new ONEFileName(Files[x].Name));
            }

            // Populate ArchiveFile Structure
            List <ONEFile> oneFiles = new List <ONEFile>(Files.Count);

            for (int x = 0; x < Files.Count; x++)
            {
                ONEFile oneFile = new ONEFile();
                oneFile.CompressedData = Files[x].CompressedData;
                oneFile.ONEFileHeader.FileNameIndex = x + 2; // ArchiveFile names always start after two blank entries, for some reason...
                oneFile.ONEFileHeader.FileSize      = oneFile.CompressedData.Length;
                oneFile.ONEFileHeader.RwVersion     = Files[x].RwVersion;
                oneFiles.Add(oneFile);
            }

            // Calculate file size.
            fileHeader.FileSize += Marshal.SizeOf(fileNameSectionHeader);
            fileHeader.FileSize += (Marshal.SizeOf <ONEFileName>() * fileNames.Count);

            for (int x = 0; x < oneFiles.Count; x++)
            {
                fileHeader.FileSize += Marshal.SizeOf(oneFiles[x].ONEFileHeader);
                fileHeader.FileSize += oneFiles[x].CompressedData.Length;
            }

            // Generate ONE file.
            List <byte> file = new List <byte>(fileHeader.FileSize + Marshal.SizeOf <ONEFileHeader>());

            file.AddRange(StructUtilities.ConvertStructureToByteArrayUnsafe(ref fileHeader));
            file.AddRange(StructUtilities.ConvertStructureToByteArrayUnsafe(ref fileNameSectionHeader));

            for (int x = 0; x < fileNames.Count; x++)
            {
                ONEFileName fileName = fileNames[x];
                file.AddRange(StructUtilities.ConvertStructureToByteArrayUnsafe(ref fileName));
            }

            for (int x = 0; x < oneFiles.Count; x++)
            {
                ONEFileHeader localFileHeader = oneFiles[x].ONEFileHeader;
                file.AddRange(StructUtilities.ConvertStructureToByteArrayUnsafe(ref localFileHeader));
                file.AddRange(oneFiles[x].CompressedData);
            }

            return(file);
        }