Пример #1
0
        public override void Flush()
        {
            const int blockSize  = 64;
            var       offsetList = new int[entries.Count];

            destination.WriteByte((byte)'T');
            destination.WriteByte((byte)'X');
            destination.WriteByte((byte)'A');
            destination.WriteByte((byte)'G');

            PTStream.WriteInt32BE(destination, entries.Count);

            var offset = PTMethods.RoundUp(0x8 + (entries.Count * 0x28), blockSize);

            for (int i = 0; i < entries.Count; i++)
            {
                var length = entries[i].Length;
                offsetList[i] = offset;

                PTStream.WriteInt32BE(destination, offset);
                PTStream.WriteInt32BE(destination, length);
                PTStream.WriteCString(destination, Path.GetFileNameWithoutExtension(entries[i].Name), 32);

                offset += PTMethods.RoundUp(length, blockSize);
            }

            for (int i = 0; i < entries.Count; i++)
            {
                destination.Position = offsetList[i];
                PTStream.CopyToPadded(entries[i].Open(), destination, blockSize, 0);
                OnFileAdded(EventArgs.Empty);
            }
        }
Пример #2
0
        public override void Flush()
        {
            // The start of the archive
            long offset = destination.Position;

            // Magic code "MRG0"
            destination.WriteByte((byte)'M');
            destination.WriteByte((byte)'R');
            destination.WriteByte((byte)'G');
            destination.WriteByte((byte)'0');

            // Number of entries in the archive
            PTStream.WriteInt32(destination, entries.Count);

            destination.Position += 8;

            // Write out the header for the archive
            int entryOffset = 16 + (entries.Count * 48);

            for (int i = 0; i < entries.Count; i++)
            {
                // Write out the file extension
                string fileExtension = Path.GetExtension(entries[i].Name);
                if (fileExtension != String.Empty)
                {
                    fileExtension = fileExtension.Substring(1);
                }

                PTStream.WriteCString(destination, fileExtension, 4, Encoding.GetEncoding("Shift_JIS"));

                // Write out the offset, length, and filename (without the extension)
                PTStream.WriteInt32(destination, entryOffset);
                PTStream.WriteInt32(destination, entries[i].Length);

                destination.Position += 4;

                PTStream.WriteCString(destination, Path.GetFileNameWithoutExtension(entries[i].Name), 32, Encoding.GetEncoding("Shift_JIS"));

                entryOffset += PTMethods.RoundUp(entries[i].Length, 16);
            }

            // Write out the file data for each entry
            for (int i = 0; i < entries.Count; i++)
            {
                PTStream.CopyToPadded(entries[i].Open(), destination, 16, 0);

                // Call the file added event
                OnFileAdded(EventArgs.Empty);
            }
        }
Пример #3
0
        public override void Flush()
        {
            const int tableStartPtr = 0x10;
            int       dataStartPtr  = PTMethods.RoundUp(tableStartPtr + (entries.Count * 0x30), 0x10); // just to be safe

            PTStream.WriteInt32BE(destination, entries.Count);
            PTStream.WriteInt32BE(destination, tableStartPtr); // pointer to table start
            PTStream.WriteInt32BE(destination, dataStartPtr);  // pointer to data start
            PTStream.WriteInt32BE(destination, 0);             // not 100% sure on this one

            int offset = dataStartPtr;

            using (var compressedStream = new MemoryStream())
            {
                for (int i = 0; i < entries.Count; i++)
                {
                    var entry       = entries[i];
                    var entryStream = entry.Open();
                    _prsCompression.Compress(entryStream, compressedStream);

                    compressedStream.Position = 0;

                    PTStream.WriteCString(destination, entry.Name, 0x20);             // name
                    PTStream.WriteInt32BE(destination, i);                            // index
                    PTStream.WriteInt32BE(destination, offset);                       // offset
                    PTStream.WriteInt32BE(destination, (int)compressedStream.Length); // compressed length
                    PTStream.WriteInt32BE(destination, (int)entryStream.Length);      // uncompressed length

                    Debug.Assert(destination.Position <= dataStartPtr, "Table overrun!");

                    var currentPos = destination.Position;
                    destination.Position = offset;
                    PTStream.CopyTo(compressedStream, destination);
                    destination.Position = currentPos;

                    offset += (int)compressedStream.Length;
                    compressedStream.Position = 0;
                    compressedStream.SetLength(0);

                    OnFileAdded(EventArgs.Empty);
                }
            }
        }
Пример #4
0
        public override void Flush()
        {
            // The start of the archive
            long offset = destination.Position;

            // Magic code "\0\0\0\0"
            destination.WriteByte(0);
            destination.WriteByte(0);
            destination.WriteByte(0);
            destination.WriteByte(0);

            // Number of entries in the archive
            PTStream.WriteInt32BE(destination, entries.Count);

            // Write out the header for the archive
            int entryOffset      = PTMethods.RoundUp(8 + (entries.Count * 8), blockSize);
            int firstEntryOffset = entryOffset;

            for (int i = 0; i < entries.Count; i++)
            {
                PTStream.WriteInt32BE(destination, entryOffset);
                PTStream.WriteInt32BE(destination, entries[i].Length);

                entryOffset += PTMethods.RoundUp(entries[i].Length, blockSize);
            }

            // Pad before writing out the file data
            while ((destination.Position - offset) % blockSize != 0)
            {
                destination.WriteByte(0);
            }

            // Write out the file data for each entry
            for (int i = 0; i < entries.Count; i++)
            {
                PTStream.CopyToPadded(entries[i].Open(), destination, blockSize, 0);

                // Call the file added event
                OnFileAdded(EventArgs.Empty);
            }
        }
Пример #5
0
        public override void Flush()
        {
            // The start of the archive
            long offset = destination.Position;

            // Magic code "AFS\0"
            destination.WriteByte((byte)'A');
            destination.WriteByte((byte)'F');
            destination.WriteByte((byte)'S');
            destination.WriteByte(0);

            // Number of entries in the archive
            PTStream.WriteInt32(destination, entries.Count);

            // Write out the header for the archive
            int entryOffset      = PTMethods.RoundUp(12 + (entries.Count * 8), blockSize);
            int firstEntryOffset = entryOffset;

            for (int i = 0; i < entries.Count; i++)
            {
                PTStream.WriteInt32(destination, entryOffset);
                PTStream.WriteInt32(destination, entries[i].Length);

                entryOffset += PTMethods.RoundUp(entries[i].Length, blockSize);
            }

            // If this is AFS v1, then the metadata offset is stored at 8 bytes before
            // the first entry offset.
            if (version == AfsVersion.Version1)
            {
                destination.Position = offset + firstEntryOffset - 8;
            }

            // Write out the metadata offset and length
            PTStream.WriteInt32(destination, entryOffset);
            PTStream.WriteInt32(destination, entries.Count * 48);

            destination.Position = offset + firstEntryOffset;

            // Write out the file data for each entry
            for (int i = 0; i < entries.Count; i++)
            {
                PTStream.CopyToPadded(entries[i].Open(), destination, blockSize, 0);

                // Call the file added event
                OnFileAdded(EventArgs.Empty);
            }

            // Write out the footer for the archive
            for (int i = 0; i < entries.Count; i++)
            {
                PTStream.WriteCString(destination, entries[i].Name, 32);

                // File timestamp
                if (HasTimestamps && !String.IsNullOrEmpty(entries[i].Path) && File.Exists(entries[i].Path))
                {
                    // File exists, let's read in the file timestamp
                    FileInfo fileInfo = new FileInfo(entries[i].Path);

                    PTStream.WriteInt16(destination, (short)fileInfo.LastWriteTime.Year);
                    PTStream.WriteInt16(destination, (short)fileInfo.LastWriteTime.Month);
                    PTStream.WriteInt16(destination, (short)fileInfo.LastWriteTime.Day);
                    PTStream.WriteInt16(destination, (short)fileInfo.LastWriteTime.Hour);
                    PTStream.WriteInt16(destination, (short)fileInfo.LastWriteTime.Minute);
                    PTStream.WriteInt16(destination, (short)fileInfo.LastWriteTime.Second);
                }
                else
                {
                    // File does not exist, just store all 0s
                    PTStream.WriteInt16(destination, 0);
                    PTStream.WriteInt16(destination, 0);
                    PTStream.WriteInt16(destination, 0);
                    PTStream.WriteInt16(destination, 0);
                    PTStream.WriteInt16(destination, 0);
                    PTStream.WriteInt16(destination, 0);
                }

                // Write out this data that I have no idea what its purpose is
                long   oldPosition = destination.Position;
                byte[] buffer      = new byte[4];

                if (version == AfsVersion.Version1)
                {
                    destination.Position = offset + 8 + (i * 8);
                }
                else
                {
                    destination.Position = offset + 4 + (i * 4);
                }

                destination.Read(buffer, 0, 4);
                destination.Position = oldPosition;
                destination.Write(buffer, 0, 4);
            }

            // Finish padding out the archive
            while ((destination.Position - offset) % blockSize != 0)
            {
                destination.WriteByte(0);
            }
        }
Пример #6
0
        public override void Flush()
        {
            // Determine the length of each entry in the header
            // and the flags that indicate what is stored in the header
            int    entryLength = 2;
            ushort flags       = 0;

            if (HasFilenames)
            {
                entryLength += 28;
                flags       |= 0x8;
            }
            if (HasFormats)
            {
                entryLength += 2;
                flags       |= 0x4;
            }
            if (HasDimensions)
            {
                entryLength += 2;
                flags       |= 0x2;
            }
            if (HasGlobalIndexes)
            {
                entryLength += 4;
                flags       |= 0x1;
            }

            // Write the start of the header
            destination.WriteByte((byte)'P');
            destination.WriteByte((byte)'V');
            destination.WriteByte((byte)'M');
            destination.WriteByte((byte)'H');

            // Offset of the first texture in the archive
            long entryOffset = PTMethods.RoundUp(12 + (entries.Count * entryLength), 16);

            PTStream.WriteInt32(destination, (int)entryOffset - 8);

            // Write out the flags
            PTStream.WriteUInt16(destination, flags);

            // Write out the number of entries
            PTStream.WriteUInt16(destination, (ushort)entries.Count);

            // We're going to be using this a few times. Might as well do this here
            long oldPosition;

            // Now, let's add the entries
            for (int i = 0; i < entries.Count; i++)
            {
                Stream entryData = entries[i].Open();

                // We need to get some information about the texture.
                // We already checked to make sure this texture is a PVR.
                // No need to check it again.
                oldPosition = entryData.Position;
                VrSharp.PvrTexture.PvrTexture texture = new VrSharp.PvrTexture.PvrTexture(entryData);
                entryData.Position = oldPosition;

                // Write out the entry number
                PTStream.WriteUInt16(destination, (ushort)i);

                // Write the information for this entry in the header
                if (HasFilenames)
                {
                    PTStream.WriteCString(destination, Path.GetFileNameWithoutExtension(entries[i].Name), 28);
                }
                if (HasFormats)
                {
                    destination.WriteByte(0);
                    destination.WriteByte((byte)texture.DataFormat);
                }
                if (HasDimensions)
                {
                    ushort dimensions = 0;
                    dimensions |= (ushort)(((byte)Math.Log(texture.TextureWidth, 2) - 2) & 0xF);
                    dimensions |= (ushort)((((byte)Math.Log(texture.TextureHeight, 2) - 2) & 0xF) << 4);
                    PTStream.WriteUInt16(destination, dimensions);
                }
                if (HasGlobalIndexes)
                {
                    PTStream.WriteUInt32(destination, texture.GlobalIndex);
                }

                // Now write out the entry information
                oldPosition          = destination.Position;
                destination.Position = entryOffset;
                entryData.Position  += texture.PvrtOffset;

                PTStream.CopyToPadded(entryData, destination, 16, 0);

                entryOffset          = destination.Position;
                destination.Position = oldPosition;

                // Call the file added event
                OnFileAdded(EventArgs.Empty);
            }
        }
Пример #7
0
        public override void Flush()
        {
            // The start of the archive
            long offset = destination.Position;

            // Magic code "NSIF/NUIF"
            if (platform == SntPlatform.Ps2)
            {
                destination.WriteByte((byte)'N');
                destination.WriteByte((byte)'S');
                destination.WriteByte((byte)'I');
                destination.WriteByte((byte)'F');
            }
            else
            {
                destination.WriteByte((byte)'N');
                destination.WriteByte((byte)'U');
                destination.WriteByte((byte)'I');
                destination.WriteByte((byte)'F');
            }

            PTStream.WriteInt32(destination, 24); // Unknown
            PTStream.WriteInt32(destination, 1);  // Unknown
            PTStream.WriteInt32(destination, 32); // Offset of the NSTL/NUTL chunk?

            // Calculate the size of the NSTL chunk
            int NSTLLength = 0;

            for (int i = 0; i < entries.Count; i++)
            {
                NSTLLength += PTMethods.RoundUp(entries[i].Length, 8);
            }

            PTStream.WriteInt32(destination, PTMethods.RoundUp(28 + (entries.Count * 28), 8) + NSTLLength);
            PTStream.WriteInt32(destination, PTMethods.RoundUp(60 + (entries.Count * 28), 8) + NSTLLength);
            PTStream.WriteInt32(destination, 24 + (entries.Count * 4));
            PTStream.WriteInt32(destination, 1);

            // NSTL/NUTL chunk
            if (platform == SntPlatform.Ps2)
            {
                destination.WriteByte((byte)'N');
                destination.WriteByte((byte)'S');
                destination.WriteByte((byte)'T');
                destination.WriteByte((byte)'L');
            }
            else
            {
                destination.WriteByte((byte)'N');
                destination.WriteByte((byte)'U');
                destination.WriteByte((byte)'T');
                destination.WriteByte((byte)'L');
            }

            PTStream.WriteInt32(destination, PTMethods.RoundUp(20 + (entries.Count * 28), 8) + NSTLLength);
            PTStream.WriteInt32(destination, 16);
            PTStream.WriteInt32(destination, 0);
            PTStream.WriteInt32(destination, entries.Count);
            PTStream.WriteInt32(destination, 28);
            PTStream.WriteInt32(destination, 28 + (entries.Count * 20));

            // Write out crap bytes
            for (int i = 0; i < entries.Count; i++)
            {
                PTStream.WriteInt32(destination, 1);
                PTStream.WriteInt32(destination, 0);
                destination.Write(new byte[] { 1, 0, 1, 0 }, 0, 4);
                PTStream.WriteInt32(destination, i);
                PTStream.WriteInt32(destination, 0);
            }

            // Write out the header for the archive
            int entryOffset = 60 + (entries.Count * 28);

            for (int i = 0; i < entries.Count; i++)
            {
                PTStream.WriteInt32(destination, entries[i].Length);
                PTStream.WriteInt32(destination, entryOffset - 32);

                entryOffset += PTMethods.RoundUp(entries[i].Length, 4);
            }

            // Write out the file data for each entry
            for (int i = 0; i < entries.Count; i++)
            {
                PTStream.CopyToPadded(entries[i].Open(), destination, 4, 0);

                // Call the file added event
                OnFileAdded(EventArgs.Empty);
            }

            // Pad before writing out the NOF0 chunk
            while ((destination.Position - offset) % 8 != 0)
            {
                destination.WriteByte(0);
            }

            // NOF0 chunk
            destination.WriteByte((byte)'N');
            destination.WriteByte((byte)'O');
            destination.WriteByte((byte)'F');
            destination.WriteByte((byte)'0');

            // Write out crap bytes
            PTStream.WriteInt32(destination, PTMethods.RoundUp(28 + (entries.Count * 4), 8));
            PTStream.WriteInt32(destination, entries.Count + 2);
            PTStream.WriteInt32(destination, 0);
            PTStream.WriteInt32(destination, 20);

            // Write out more unknown stuff
            for (int i = 0; i < entries.Count; i++)
            {
                PTStream.WriteInt32(destination, 32 + (entries.Count * 20) + (i * 8));
            }

            PTStream.WriteInt32(destination, 24);

            // Pad before we write NEND
            // Finish padding out the archive
            while ((destination.Position - offset) % 16 != 0)
            {
                destination.WriteByte(0);
            }

            destination.WriteByte((byte)'N');
            destination.WriteByte((byte)'E');
            destination.WriteByte((byte)'N');
            destination.WriteByte((byte)'D');

            while ((destination.Position - offset) % 16 != 0)
            {
                destination.WriteByte(0);
            }
        }
Пример #8
0
        public override void Flush()
        {
            // The start of the archive
            long offset = destination.Position;

            // Puyo Tools is only capable of building U8 archives that do not contain directories.
            // It's just very difficult to do with the way Puyo Tools is structured.

            // First things first, let's get the header size
            int headerSize = ((entries.Count + 1) * 12) + 1;

            for (int i = 0; i < entries.Count; i++)
            {
                headerSize += entries[i].Name.Length + 1;
            }

            // Get the name and data offset
            int nameOffset = 0;
            int dataOffset = PTMethods.RoundUp(0x20 + headerSize, 32);

            // Start writing out the header
            destination.WriteByte((byte)'U');
            destination.WriteByte(0xAA);
            destination.WriteByte((byte)'8');
            destination.WriteByte((byte)'-');

            PTStream.WriteUInt32BE(destination, 0x20);      // Root node offset (always 0x20)
            PTStream.WriteInt32BE(destination, headerSize); // Header size
            PTStream.WriteInt32BE(destination, dataOffset); // Data offset

            // Pad
            while ((destination.Position - offset) % 32 != 0)
            {
                destination.WriteByte(0);
            }

            // Write the root node
            destination.WriteByte(1);
            destination.WriteByte((byte)(nameOffset >> 16));
            PTStream.WriteUInt16BE(destination, (ushort)(nameOffset & 0xFFFF));
            PTStream.WriteInt32BE(destination, 0);
            PTStream.WriteInt32BE(destination, entries.Count + 1);

            nameOffset++;

            // Write out the file nodes
            for (int i = 0; i < entries.Count; i++)
            {
                destination.WriteByte(0);
                destination.WriteByte((byte)(nameOffset >> 16));
                PTStream.WriteUInt16BE(destination, (ushort)(nameOffset & 0xFFFF));
                PTStream.WriteInt32BE(destination, dataOffset);
                PTStream.WriteInt32BE(destination, entries[i].Length);

                nameOffset += entries[i].Name.Length + 1;
                dataOffset += PTMethods.RoundUp(entries[i].Length, 32);
            }

            // Write out the filename table
            PTStream.WriteCString(destination, String.Empty, 1);
            for (int i = 0; i < entries.Count; i++)
            {
                PTStream.WriteCString(destination, entries[i].Name, entries[i].Name.Length + 1);
            }

            // Pad
            while ((destination.Position - offset) % 32 != 0)
            {
                destination.WriteByte(0);
            }

            // Write the file data
            for (int i = 0; i < entries.Count; i++)
            {
                PTStream.CopyToPadded(entries[i].Open(), destination, 32, 0);

                // Call the file added event
                OnFileAdded(EventArgs.Empty);
            }
        }
Пример #9
0
    // Build GAME.DAT using files from the specified directory
    public static void Build(string executable, string inDir, string gameDat)
    {
        Console.Write("\nBuilding ...");

        using (FileStream exeStream = File.Open(executable, FileMode.Open, FileAccess.ReadWrite))
        {
            // Determine the game version
            GameVersion gameVersion = GameVersion.Unknown;
            if (exeStream.Length == 2678816) // Wii version
            {
                gameVersion = GameVersion.Wii;
            }
            else if (exeStream.Length == 2716853) // PSP version
            {
                gameVersion = GameVersion.PSP;
            }
            else
            {
                return;
            }

            uint numFiles = 0;
            if (gameVersion == GameVersion.Wii)
            {
                exeStream.Position = 0x18A058;
            }
            else if (gameVersion == GameVersion.PSP)
            {
                exeStream.Position = 0x1978FC;
            }

            // Get the number of files in the file entry table
            exeStream.Position += 20;
            if (gameVersion == GameVersion.Wii)
            {
                numFiles            = PTStream.ReadUInt32BE(exeStream);
                exeStream.Position += 152; // Now go to the position of the first file in the file entry table
            }
            else if (gameVersion == GameVersion.PSP)
            {
                numFiles            = PTStream.ReadUInt32(exeStream);
                exeStream.Position += 136; // Now go to the position of the first file in the file entry table
            }

            string[] fileList = new string[numFiles];

            Console.WriteLine(" " + numFiles + " files detected.");

            // Now let's make sure all the files exist
            for (uint i = 0; i < numFiles; i++)
            {
                string[] file = Directory.GetFiles(inDir, i.ToString("D4") + ".*");
                if (file.Length == 0)
                {
                    Console.WriteLine("{0} does not exist. Terminating.", i.ToString("D4"));
                    return;
                }
                else if (file.Length > 1)
                {
                    Console.WriteLine("Multiple copies of {0} exist. Terminating.", i.ToString("D4"));
                    return;
                }

                fileList[i] = file[0];
            }

            // Ok, looks like we're good. Let's build GAME.DAT
            using (FileStream gameDatStream = File.Create(gameDat))
            {
                uint offset = 0;
                for (uint i = 0; i < numFiles; i++)
                {
                    Console.Write("Adding file " + Path.GetFileName(fileList[i]) + " ... ");

                    // Go to the next file entry
                    NextFileEntry(exeStream);

                    exeStream.Position += 4;

                    using (FileStream inStream = File.OpenRead(fileList[i]))
                    {
                        if (gameVersion == GameVersion.Wii)
                        {
                            PTStream.WriteUInt32BE(exeStream, offset);
                            PTStream.WriteUInt32BE(exeStream, (uint)inStream.Length);
                        }
                        else if (gameVersion == GameVersion.PSP)
                        {
                            PTStream.WriteUInt32(exeStream, offset);
                            PTStream.WriteUInt32(exeStream, (uint)inStream.Length);
                        }

                        PTStream.CopyPartToPadded(inStream, gameDatStream, (int)inStream.Length, 2048, 0);

                        offset += (uint)PTMethods.RoundUp((int)inStream.Length, 2048);
                    }

                    exeStream.Position += 12;

                    Console.WriteLine("OK");
                }
            }
        }
    }