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); } }
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); }
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); }
/// <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); } }
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); }
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); }
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); }
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); }
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; }
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(); } } }
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); } } }
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); } }
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); }
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); }
/// <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); }
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 })); }
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); } }
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); }
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' })); }
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); } }
/// <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; } } }
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); }
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); }
/// <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 })); }
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' })); }