Implements the Quetzal saved-game file specification by holding a list of typed data chunks which can be read from or written to streams.
http://www.ifarchive.org/if-archive/infocom/interpreters/specification/savefile_14.txt
示例#1
0
文件: Quetzal.cs 项目: DESYS21/FyreVM
        /// <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);
        }
示例#2
0
        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);
        }
示例#3
0
        /// <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;
        }