Beispiel #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);
            }
        }
Beispiel #2
0
        public override Stream OpenEntry(ArchiveEntry entry)
        {
            // If this archive does not contain any global indexes, then just return the data as is.
            if (!hasGlobalIndexes)
            {
                return(base.OpenEntry(entry));
            }

            long oldPosition = archiveData.Position;

            MemoryStream data = new MemoryStream();

            // Write out the GBIX header
            data.WriteByte((byte)'G');
            data.WriteByte((byte)'B');
            data.WriteByte((byte)'I');
            data.WriteByte((byte)'X');
            PTStream.WriteInt32(data, 8);

            archiveData.Position = 0xC + (entry.Index * tableEntryLength) + globalIndexOffset;
            PTStream.WriteUInt32(data, PTStream.ReadUInt32(archiveData));

            data.Position += 4;

            // Now copy over the file data
            archiveData.Position = entry.Offset;
            PTStream.CopyPartTo(archiveData, data, entry.Length);

            archiveData.Position = oldPosition;
            data.Position        = 0;

            return(data);
        }
        public OneStorybookArchiveReader(Stream source) : base(source)
        {
            _prsCompression = new PrsCompression();

            // Get the number of entries in the archive
            int numEntries = PTStream.ReadInt32BE(source);

            entries = new ArchiveEntryCollection(this, numEntries);

            // Read in all the entries
            for (int i = 0; i < numEntries; i++)
            {
                string entryFilename = PTStream.ReadCStringAt(source, 0x10 + (i * 0x30), 0x20);

                source.Position = 0x34 + (i * 0x30);
                int entryOffset = PTStream.ReadInt32BE(source);
                int entryLength = PTStream.ReadInt32BE(source);

                // Add this entry to the collection
                entries.Add(startOffset + entryOffset, entryLength, entryFilename);
            }

            // Set the position of the stream to the end of the file
            source.Seek(0, SeekOrigin.End);
        }
Beispiel #4
0
        public TexArchiveReader(Stream source) : base(source)
        {
            // Get the number of entries in the archive
            source.Position += 4;
            int numEntries = PTStream.ReadInt32(source);

            entries = new ArchiveEntryCollection(this, numEntries);

            source.Position += 8;

            // Read in all the entries
            for (int i = 0; i < numEntries; i++)
            {
                // Read in the entry filename extension, offset, length, and filename without the extension
                string entryFileExtension = PTStream.ReadCString(source, 4, Encoding.GetEncoding("Shift_JIS"));
                int    entryOffset        = PTStream.ReadInt32(source);
                int    entryLength        = PTStream.ReadInt32(source);
                string entryFilename      = PTStream.ReadCString(source, 20, Encoding.GetEncoding("Shift_JIS"));

                if (entryFileExtension != String.Empty)
                {
                    entryFileExtension = "." + entryFileExtension;
                }

                // Add this entry to the collection
                entries.Add(startOffset + entryOffset, entryLength, entryFilename + entryFileExtension);
            }

            // Set the position of the stream to the end of the file
            source.Seek(0, SeekOrigin.End);
        }
Beispiel #5
0
 /// <summary>
 /// Extracts the specified entry to a file.
 /// </summary>
 /// <param name="entry">An archive entry.</param>
 /// <param name="path">The path to extract the file to.</param>
 public void ExtractToFile(ArchiveEntry entry, string path)
 {
     using (Stream source = OpenEntry(entry), destination = File.Create(path))
     {
         PTStream.CopyTo(source, destination);
     }
 }
Beispiel #6
0
        protected override MemoryStream EncodePalette()
        {
            // Calculate what the length of the palette will be
            int paletteLength = 16 + (paletteEntries * pixelCodec.Bpp / 8);

            MemoryStream destination = new MemoryStream(paletteLength);

            // Write out the PVPL header
            destination.WriteByte((byte)'P');
            destination.WriteByte((byte)'V');
            destination.WriteByte((byte)'P');
            destination.WriteByte((byte)'L');

            PTStream.WriteInt32(destination, paletteLength - 8);

            destination.WriteByte((byte)pixelFormat);
            destination.WriteByte(0);

            PTStream.WriteUInt32(destination, 0);

            PTStream.WriteUInt16(destination, paletteEntries);

            // Write the palette data
            byte[] palette = pixelCodec.EncodePalette(decodedPalette, paletteEntries);
            destination.Write(palette, 0, palette.Length);

            return(destination);
        }
Beispiel #7
0
        public override Stream OpenEntry(ArchiveEntry entry)
        {
            // Some Billy Hatcher textures have an oddity where the texture length is 16 more than what it
            // actually should be. This seems to only effect the last texture of a GVM, and only some of them
            // are affected. In that case, we will "fix" the GVRs in question.
            bool needToFix = (entry.Index == entries.Count - 1 && this.needToFix);

            // If this archive does not contain any global indicies, then just return the data as is.
            if (!hasGlobalIndexes && !needToFix)
            {
                return(base.OpenEntry(entry));
            }

            long oldPosition = archiveData.Position;

            MemoryStream data = new MemoryStream();

            // Write out the GBIX header, if this archive contains global indexes
            if (hasGlobalIndexes)
            {
                data.WriteByte((byte)'G');
                data.WriteByte((byte)'B');
                data.WriteByte((byte)'I');
                data.WriteByte((byte)'X');
                PTStream.WriteInt32(data, 8);

                archiveData.Position = 0xC + (entry.Index * tableEntryLength) + globalIndexOffset;
                PTStream.WriteInt32BE(data, PTStream.ReadInt32BE(archiveData));

                data.Position += 4;
            }

            // Now copy over the file data
            archiveData.Position = entry.Offset;
            PTStream.CopyPartTo(archiveData, data, entry.Length);

            // Fix the texture lengths for the textures that need to be "fixed"
            if (needToFix)
            {
                if (hasGlobalIndexes)
                {
                    data.Position = 0x14;
                }
                else
                {
                    data.Position = 0x4;
                }

                uint actualLength = PTStream.ReadUInt32(data);
                data.Position -= 4;
                PTStream.WriteUInt32(data, actualLength - 16);
            }

            archiveData.Position = oldPosition;
            data.Position        = 0;

            return(data);
        }
Beispiel #8
0
 public override bool Is(Stream source, int length, string fname)
 {
     return(length > 36 &&
            (PTStream.Contains(source, 0, new byte[] { (byte)'N', (byte)'U', (byte)'I', (byte)'F' }) &&
             PTStream.Contains(source, 32, new byte[] { (byte)'N', (byte)'U', (byte)'T', (byte)'L' })) ||
            (PTStream.Contains(source, 0, new byte[] { (byte)'N', (byte)'S', (byte)'I', (byte)'F' }) &&
             PTStream.Contains(source, 32, new byte[] { (byte)'N', (byte)'S', (byte)'T', (byte)'L' })) &&
            PTStream.ReadInt32At(source, source.Position + 8) == 1);
 }
Beispiel #9
0
        public SntArchiveReader(Stream source) : base(source)
        {
            // Get the number of entries in the archive
            source.Position += 48;
            int numEntries = PTStream.ReadInt32(source);

            entries = new ArchiveEntryCollection(this, numEntries);

            source.Position += 8 + (numEntries * 20);

            // Read in all the entries
            for (int i = 0; i < numEntries; i++)
            {
                // Readin the entry offset and length
                int entryLength = PTStream.ReadInt32(source);
                int entryOffset = PTStream.ReadInt32(source) + 32;

                // If this archive contains GIM textures, then it's possible that they may contain filenames.
                // Let's check and see
                string entryFname = String.Empty;
                if (entryLength > 40)
                {
                    long oldPosition = source.Position;
                    source.Position = startOffset + entryOffset;

                    if ((new GimTexture()).Is(source, entryLength, String.Empty))
                    {
                        // It's a GIM texture. Let's try to find a filename
                        source.Position += 36;
                        long fnameOffset = PTStream.ReadInt32(source) + 48;

                        if (fnameOffset < source.Length)
                        {
                            source.Position = startOffset + entryOffset + fnameOffset;
                            entryFname      = Path.GetFileNameWithoutExtension(PTStream.ReadCString(source, (int)(source.Length - fnameOffset)));

                            if (entryFname != String.Empty)
                            {
                                entryFname += ".gim";
                            }
                        }
                    }

                    source.Position = oldPosition;
                }

                // Add this entry to the collection
                entries.Add(startOffset + entryOffset, entryLength, entryFname);
            }

            // Set the position of the stream to the end of the file
            source.Seek(0, SeekOrigin.End);
        }
Beispiel #10
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);
            }
        }
    private static void NextFileEntry(Stream input)
    {
        input.Position += 16;
        while (input.Position < input.Length)
        {
            if (PTStream.ReadUInt32(input) == 0xFFFFFFFF)
            {
                break;
            }

            input.Position -= 3;
        }
        input.Position -= 20;
    }
Beispiel #12
0
        private void OpenTexture(Stream data, string fname, TextureFormat format)
        {
            TextureViewer viewer = new TextureViewer();

            long oldPosition = data.Position;

            try
            {
                viewer.OpenTexture(data, fname, format);
                viewer.Show();
            }
            catch (TextureNeedsPaletteException)
            {
                ArchiveInfo info = openedArchives.Peek();

                // Seems like we need a palette for this texture. Let's try to find one.
                string textureName      = Path.GetFileNameWithoutExtension(fname) + Texture.GetModule(format).PaletteFileExtension;
                int    paletteFileIndex = -1;

                for (int i = 0; i < info.Archive.Entries.Count; i++)
                {
                    if (info.Archive.Entries[i].Name.ToLower() == textureName.ToLower())
                    {
                        paletteFileIndex = i;
                        break;
                    }
                }

                // Let's see if we found the palette file. And if so, open it up.
                // Due to the nature of how this works, we need to copy the palette data to another stream first
                if (paletteFileIndex != -1)
                {
                    Stream entryData     = info.Archive.OpenEntry(paletteFileIndex);
                    int    paletteLength = (int)entryData.Length;

                    // Get the palette data (we may need to copy over the data to another stream)
                    Stream paletteData = new MemoryStream();
                    PTStream.CopyTo(entryData, paletteData);
                    paletteData.Position = 0;

                    // Now open the texture
                    data.Position = oldPosition;
                    viewer.OpenTexture(data, fname, paletteData, format);
                    viewer.Show();
                }
            }
        }
Beispiel #13
0
        public TxdStorybookArchiveReader(Stream source) : base(source)
        {
            var fileCount = PTStream.ReadInt32BEAt(source, 0x4);

            entries = new ArchiveEntryCollection(this, fileCount);

            for (int i = 0; i < fileCount; i++)
            {
                var fileName = PTStream.ReadCStringAt(source, 0x10 + (i * 0x28), 32);
                var offset   = PTStream.ReadUInt32BEAt(source, 0x08 + (i * 0x28));
                var length   = PTStream.ReadInt32BEAt(source, 0x0C + (i * 0x28));

                fileName = string.IsNullOrWhiteSpace(fileName) ? fileName : Path.ChangeExtension(fileName, "GVR");

                entries.Add(startOffset + offset, length, fileName);
            }
        }
        public override bool Is(Stream source, int length, string fname)
        {
            if (PTStream.ReadUInt32BEAt(source, 0x4) != 0x10)
            {
                return(false);
            }

            var i = PTStream.ReadUInt32BEAt(source, 0xC);

            if (i != 0xFFFFFFFF && i != 0x00000000)
            {
                return(false);
            }

            source.Seek(0, SeekOrigin.Begin);
            return(true);
        }
        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);
                }
            }
        }
Beispiel #16
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);
            }
        }
Beispiel #17
0
        public AfsArchiveReader(Stream source) : base(source)
        {
            // Get the number of entries in the archive
            source.Position += 4;
            int numEntries = PTStream.ReadInt32(source);

            entries = new ArchiveEntryCollection(this, numEntries);

            // Get the offset of the metadata
            source.Position += (numEntries * 8);
            int metadataOffset = PTStream.ReadInt32(source);

            // If the offset isn't stored there, then it is stored right before the offset of the first entry
            if (metadataOffset == 0)
            {
                source.Position = startOffset + 8;
                source.Position = PTStream.ReadInt32(source) - 8;
                metadataOffset  = PTStream.ReadInt32(source);
            }

            // Read in all the entries
            for (int i = 0; i < numEntries; i++)
            {
                // Read in the entry offset and length
                source.Position = startOffset + 8 + (i * 8);
                int entryOffset = PTStream.ReadInt32(source);
                int entryLength = PTStream.ReadInt32(source);

                // Read in the entry file name
                source.Position = metadataOffset + (i * 48);
                string entryFname = PTStream.ReadCString(source, 32);

                // Add this entry to the collection
                entries.Add(startOffset + entryOffset, entryLength, entryFname);
            }

            // Set the position of the stream to the end of the file
            source.Seek(0, SeekOrigin.End);
        }
Beispiel #18
0
        public AcxArchiveReader(Stream source) : base(source)
        {
            // Get the number of entries in the archive
            source.Position += 4;
            int numEntries = PTStream.ReadInt32BE(source);

            entries = new ArchiveEntryCollection(this, numEntries);

            // Read in all the entries
            for (int i = 0; i < numEntries; i++)
            {
                // Read in the entry offset and length
                int entryOffset = PTStream.ReadInt32BE(source);
                int entryLength = PTStream.ReadInt32BE(source);

                // Add this entry to the collection
                entries.Add(startOffset + entryOffset, entryLength, String.Empty);
            }

            // Set the position of the stream to the end of the file
            source.Seek(0, SeekOrigin.End);
        }
        public OneUnleashedArchiveReader(Stream source) : base(source)
        {
            // Get the number of entries in the archive
            source.Position += 4;
            int numEntries = PTStream.ReadInt32(source);

            entries = new ArchiveEntryCollection(this, numEntries);

            // Read in all the entries
            for (int i = 0; i < numEntries; i++)
            {
                // Read in the entry filename, offset, and length
                string entryFilename = PTStream.ReadCString(source, 56);
                int    entryOffset   = PTStream.ReadInt32(source);
                int    entryLength   = PTStream.ReadInt32(source);

                // Add this entry to the collection
                entries.Add(startOffset + entryOffset, entryLength, entryFilename);
            }

            // Set the position of the stream to the end of the file
            source.Seek(0, SeekOrigin.End);
        }
Beispiel #20
0
 /// <summary>
 /// Determines if the data is in the specified format.
 /// </summary>
 /// <param name="source">The stream to read from.</param>
 /// <param name="length">Number of bytes to read.</param>
 /// <param name="fname">Name of the file.</param>
 /// <returns>True if the data is in the specified format, false otherwise.</returns>
 public override bool Is(Stream source, int length, string fname)
 {
     return(length > 16 &&
            PTStream.Contains(source, 0, new byte[] { (byte)'C', (byte)'N', (byte)'X', 0x2 }) &&
            PTStream.ReadInt32BEAt(source, source.Position + 8) + 16 == length);
 }
Beispiel #21
0
 public override bool Is(Stream source, int length, string fname)
 {
     return(length > 8 && PTStream.Contains(source, 0, new byte[] { (byte)'A', (byte)'F', (byte)'S', 0 }));
 }
Beispiel #22
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);
            }
        }
Beispiel #23
0
        public NarcArchiveReader(Stream source) : base(source)
        {
            // Read the archive header
            source.Position += 12;
            ushort fatbOffset = PTStream.ReadUInt16(source); // Should always be 0x10

            // Read the FATB chunk
            source.Position = startOffset + fatbOffset + 4;
            uint fntbOffset = fatbOffset + PTStream.ReadUInt32(source);


            // Get the number of entries in the archive
            int numEntries = PTStream.ReadInt32(source);

            entries = new ArchiveEntryCollection(this, numEntries);

            // Let's check to see if this is a Puyo Tetris PS3 NARC by checking the offset of the first file.
            // It seems that offsets are stored differently than a normal NARC.
            bool isPs3Narc = (PTStream.ReadUInt32(source) == 0);

            // This is a Puyo Tetris PS3 NARC.
            if (isPs3Narc)
            {
                // Read the FNTB chunk
                source.Position = startOffset + fntbOffset + 4;
                uint fimgOffset     = fntbOffset + PTStream.ReadUInt32(source);
                bool hasFilenames   = (fimgOffset - fntbOffset != 16);
                uint filenameOffset = fntbOffset + 8 + PTStream.ReadUInt32(source);

                // Read in all the entries
                source.Position = startOffset + fatbOffset + 12;
                for (int i = 0; i < numEntries; i++)
                {
                    // Read the entry offset and length
                    int entryOffset = PTStream.ReadInt32(source);
                    int entryLength = PTStream.ReadInt32(source) - entryOffset;

                    // Read the filename (if it has one)
                    string entryFname = String.Empty;
                    if (hasFilenames)
                    {
                        long oldPosition = source.Position;
                        source.Position = startOffset + filenameOffset;

                        byte fnameLength = PTStream.ReadByte(source);

                        // Puyo Tools can't handle directory names. Just skip over them for now.
                        if ((fnameLength & 0x80) != 0)
                        {
                            // Go only up to fimgOffset to prevent an infinite loop
                            // (though that should never happen for a properly formatted NARC).
                            while ((fnameLength & 0x80) != 0 && filenameOffset < fimgOffset)
                            {
                                fnameLength     &= 0x7F;
                                filenameOffset  += (uint)(fnameLength + 4);
                                source.Position += fnameLength + 3;
                                fnameLength      = PTStream.ReadByte(source);
                            }
                        }

                        entryFname      = PTStream.ReadCString(source, fnameLength);
                        filenameOffset += (uint)(fnameLength + 1);

                        source.Position = oldPosition;
                    }

                    // Add this entry to the collection
                    entries.Add(startOffset + fimgOffset + 8 + entryOffset, entryLength, entryFname);
                }
            }

            // This is a NDS NARC.
            else
            {
                // Read the FNTB chunk
                source.Position = startOffset + fntbOffset + 4;
                bool hasFilenames   = (PTStream.ReadUInt32(source) == 8);
                uint filenameOffset = fntbOffset + 8 + PTStream.ReadUInt32(source);

                // Read in all the entries
                source.Position = startOffset + fatbOffset + 12;
                for (int i = 0; i < numEntries; i++)
                {
                    // Read the entry offset and length
                    int entryOffset = PTStream.ReadInt32(source);
                    int entryLength = PTStream.ReadInt32(source) - entryOffset;

                    // Read the filename (if it has one)
                    string entryFname = String.Empty;
                    if (hasFilenames)
                    {
                        long oldPosition = source.Position;
                        source.Position = startOffset + filenameOffset;

                        byte fnameLength = PTStream.ReadByte(source);
                        entryFname      = PTStream.ReadCString(source, fnameLength);
                        filenameOffset += (uint)(fnameLength + 1);

                        source.Position = oldPosition;
                    }

                    // Add this entry to the collection
                    entries.Add(startOffset + entryOffset, entryLength, entryFname);
                }
            }

            // Set the position of the stream to the end of the file
            source.Seek(0, SeekOrigin.End);
        }
Beispiel #24
0
 public override bool Is(Stream source, int length, string fname)
 {
     return(length > 12 && PTStream.Contains(source, 0, new byte[] { (byte)'P', (byte)'V', (byte)'M', (byte)'H' }));
 }
Beispiel #25
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);
            }
        }
Beispiel #26
0
        /// <summary>
        /// Decompress data from a stream.
        /// </summary>
        /// <param name="source">The stream to read from.</param>
        /// <param name="destination">The stream to write to.</param>
        public override void Decompress(Stream source, Stream destination)
        {
            source.Position += 8;

            // Get the source length and destination length
            int sourceLength      = PTStream.ReadInt32BE(source) + 16;
            int destinationLength = PTStream.ReadInt32BE(source);

            // Set the source, destination, and buffer pointers
            int sourcePointer      = 0x10;
            int destinationPointer = 0x0;
            int bufferPointer      = 0x0;

            // Initalize the buffer
            byte[] buffer = new byte[0x800];

            // Start decompression
            while (sourcePointer < sourceLength)
            {
                byte flag = PTStream.ReadByte(source);
                sourcePointer++;

                for (int i = 0; i < 4; i++)
                {
                    byte   value;
                    ushort matchPair;
                    int    matchDistance, matchLength;

                    switch (flag & 0x3)
                    {
                    // Jump to the next 0x800 boundary
                    case 0:
                        value = PTStream.ReadByte(source);

                        sourcePointer   += value + 1;
                        source.Position += value;

                        i = 3;
                        break;

                    // Not compressed, single byte
                    case 1:
                        value = PTStream.ReadByte(source);
                        sourcePointer++;

                        destination.WriteByte(value);
                        destinationPointer++;

                        buffer[bufferPointer] = value;
                        bufferPointer         = (bufferPointer + 1) & 0x7FF;
                        break;

                    // Compressed
                    case 2:
                        matchPair      = PTStream.ReadUInt16BE(source);
                        sourcePointer += 2;

                        matchDistance = (matchPair >> 5) + 1;
                        matchLength   = (matchPair & 0x1F) + 4;

                        for (int j = 0; j < matchLength; j++)
                        {
                            destination.WriteByte(buffer[(bufferPointer - matchDistance) & 0x7FF]);
                            destinationPointer++;

                            buffer[bufferPointer] = buffer[(bufferPointer - matchDistance) & 0x7FF];
                            bufferPointer         = (bufferPointer + 1) & 0x7FF;
                        }
                        break;

                    // Not compressed, multiple bytes
                    case 3:
                        matchLength = PTStream.ReadByte(source);
                        sourcePointer++;

                        for (int j = 0; j < matchLength; j++)
                        {
                            value = PTStream.ReadByte(source);
                            sourcePointer++;

                            destination.WriteByte(value);
                            destinationPointer++;

                            buffer[bufferPointer] = value;
                            bufferPointer         = (bufferPointer + 1) & 0x7FF;
                        }
                        break;
                    }

                    // Check to see if we reached the end of the source
                    if (sourcePointer >= sourceLength)
                    {
                        break;
                    }

                    // Check to see if we wrote too much data to the destination
                    if (destinationPointer > destinationLength)
                    {
                        throw new Exception("Too much data written to the destination.");
                    }

                    flag >>= 2;
                }
            }
        }
Beispiel #27
0
 public override bool Is(Stream source, int length, string fname)
 {
     return(length > 12 &&
            PTStream.Contains(source, 0, new byte[] { (byte)'N', (byte)'A', (byte)'R', (byte)'C', 0xFE, 0xFF, 0x00, 0x01 }) &&
            PTStream.ReadInt32At(source, source.Position + 8) == length);
 }
Beispiel #28
0
        public PvmArchiveReader(Stream source) : base(source)
        {
            // The offset of the first entry
            source.Position += 4;
            int entryOffset  = PTStream.ReadInt32(source) + 8;
            int headerOffset = 0xC;

            // Read what properties this archive stores for each texture
            byte properties = PTStream.ReadByte(source);

            hasFilenames     = (properties & (1 << 3)) > 0;
            hasFormats       = (properties & (1 << 2)) > 0;
            hasDimensions    = (properties & (1 << 1)) > 0;
            hasGlobalIndexes = (properties & (1 << 0)) > 0;
            source.Position++;

            // Determine the size of each entry in the entry table
            tableEntryLength = 2;
            if (hasFilenames)
            {
                tableEntryLength += 28;
            }
            if (hasFormats)
            {
                tableEntryLength += 2;
            }
            if (hasDimensions)
            {
                tableEntryLength += 2;
            }

            if (hasGlobalIndexes)
            {
                globalIndexOffset = tableEntryLength;
                tableEntryLength += 4;
            }

            // Get the number of entries in the archive
            ushort numEntries = PTStream.ReadUInt16(source);

            entries = new ArchiveEntryCollection(this, numEntries);

            // Read in all the entries
            for (int i = 0; i < numEntries; i++)
            {
                // We need to need to determine the offset based on the length,
                // which is stored in the texture data.
                // We already have the entry offset
                source.Position = startOffset + entryOffset + 4;
                int entryLength = PTStream.ReadInt32(source) + 8;

                string entryFname = String.Empty;
                if (hasFilenames)
                {
                    source.Position = startOffset + headerOffset + 2;
                    entryFname      = PTStream.ReadCString(source, 28) + ".pvr";
                    headerOffset   += tableEntryLength;
                }

                // Add this entry to the collection
                entries.Add(startOffset + entryOffset, entryLength, entryFname);

                entryOffset += entryLength;
            }

            // Set the position of the stream to the end of the file
            source.Seek(0, SeekOrigin.End);
        }
Beispiel #29
0
 /// <summary>
 /// Determines if the data is in the specified format.
 /// </summary>
 /// <param name="source">The stream to read from.</param>
 /// <param name="length">Number of bytes to read.</param>
 /// <param name="fname">Name of the file.</param>
 /// <returns>True if the data is in the specified format, false otherwise.</returns>
 public override bool Is(Stream source, int length, string fname)
 {
     return(Path.GetExtension(fname).ToLower() == ".prs" && length > 2 && PTStream.Contains(source, length - 2, new byte[] { 0, 0 }));
 }
Beispiel #30
0
 public override bool Is(Stream source, int length, string fname)
 {
     return(length > 16 && PTStream.Contains(source, 0, new byte[] { (byte)'T', (byte)'E', (byte)'X', (byte)'0' }));
 }