/// <summary> /// Loads a collection of chunks from a Quetzal file. /// </summary> /// <param name="stream">The stream to read from.</param> /// <returns>A new <see cref="Quetzal"/> instance initialized /// from the stream.</returns> /// <remarks> /// Duplicate chunks are not supported by this class. Only the last /// chunk of a given type will be available. /// </remarks> public static Quetzal FromStream(Stream stream) { Quetzal result = new Quetzal(); uint type = BigEndian.ReadInt32(stream); if (type != FORM && type != LIST && type != CAT_) { throw new ArgumentException("Invalid IFF type"); } int length = (int)BigEndian.ReadInt32(stream); byte[] buffer = new byte[length]; int amountRead = stream.Read(buffer, 0, (int)length); if (amountRead < length) { throw new ArgumentException("Quetzal file is too short"); } stream = new MemoryStream(buffer); type = BigEndian.ReadInt32(stream); if (type != IFZS) { throw new ArgumentException("Wrong IFF sub-type: not a Quetzal file"); } while (stream.Position < stream.Length) { type = BigEndian.ReadInt32(stream); length = (int)BigEndian.ReadInt32(stream); byte[] chunk = new byte[length]; amountRead = stream.Read(chunk, 0, length); if (amountRead < length) { throw new ArgumentException("Chunk extends past end of file"); } result.chunks[type] = chunk; } return(result); }
private void SaveToStream(Stream stream, uint destType, uint destAddr) { if (stream == null) { return; } Quetzal quetzal = new Quetzal(); // 'IFhd' identifies the first 128 bytes of the game file quetzal["IFhd"] = image.GetOriginalIFHD(); // 'CMem' or 'UMem' are the compressed/uncompressed contents of RAM byte[] origRam = image.GetOriginalRAM(); byte[] newRomRam = image.GetMemory(); int ramSize = (int)(image.EndMem - image.RamStart); #if !SAVE_UNCOMPRESSED quetzal["CMem"] = Quetzal.CompressMemory( origRam, 0, origRam.Length, newRomRam, (int)image.RamStart, ramSize); #else byte[] umem = new byte[ramSize + 4]; BigEndian.WriteInt32(umem, 0, (uint)ramSize); Array.Copy(newRomRam, (int)image.RamStart, umem, 4, ramSize); quetzal["UMem"] = umem; #endif // 'Stks' is the contents of the stack, with a stub on top // identifying the destination of the save opcode. PushCallStub(new CallStub(destType, destAddr, pc, fp)); byte[] trimmed = new byte[sp]; Array.Copy(stack, trimmed, (int)sp); quetzal["Stks"] = trimmed; PopCallStub(); // 'MAll' is the list of heap blocks if (heap != null) quetzal["MAll"] = heap.Save(); else { } quetzal.WriteToStream(stream); }
/// <summary> /// Loads a collection of chunks from a Quetzal file. /// </summary> /// <param name="stream">The stream to read from.</param> /// <returns>A new <see cref="Quetzal"/> instance initialized /// from the stream.</returns> /// <remarks> /// Duplicate chunks are not supported by this class. Only the last /// chunk of a given type will be available. /// </remarks> public static Quetzal FromStream(Stream stream) { Quetzal result = new Quetzal(); uint type = BigEndian.ReadInt32(stream); if (type != FORM && type != LIST && type != CAT_) throw new ArgumentException("Invalid IFF type"); int length = (int)BigEndian.ReadInt32(stream); byte[] buffer = new byte[length]; int amountRead = stream.Read(buffer, 0, (int)length); if (amountRead < length) throw new ArgumentException("Quetzal file is too short"); stream = new MemoryStream(buffer); type = BigEndian.ReadInt32(stream); if (type != IFZS) throw new ArgumentException("Wrong IFF sub-type: not a Quetzal file"); while (stream.Position < stream.Length) { type = BigEndian.ReadInt32(stream); length = (int)BigEndian.ReadInt32(stream); byte[] chunk = new byte[length]; amountRead = stream.Read(chunk, 0, length); if (amountRead < length) throw new ArgumentException("Chunk extends past end of file"); result.chunks[type] = chunk; } return result; }