示例#1
0
        /// <summary>
        /// Saves the serialized <see cref="GameBox{T}"/> on a disk.
        /// </summary>
        /// <param name="fileName">Relative or absolute file path.</param>
        /// <param name="remap">What to remap the newest node IDs to. Used for older games.</param>
        public void Save(string fileName, ClassIDRemap remap)
        {
            using (var fs = File.OpenWrite(fileName))
                Save(fs, remap);

            Log.Write($"GBX file {fileName} saved.");
        }
示例#2
0
        public void Write(GameBoxWriter w, ClassIDRemap remap)
        {
            using (MemoryStream ms = new MemoryStream())
                using (GameBoxWriter bodyW = new GameBoxWriter(ms))
                {
                    (Body as ILookbackable).IdWritten = false;
                    (Body as ILookbackable).IdStrings.Clear();
                    Body.AuxilaryNodes.Clear();

                    Log.Write("Writing the body...");

                    Body.Write(bodyW, remap); // Body is written first so that the aux node count is determined properly

                    Log.Write("Writing the header...");

                    (Header as ILookbackable).IdWritten = false;
                    (Header as ILookbackable).IdStrings.Clear();
                    Header.Write(w, Body.AuxilaryNodes.Count + 1, remap);

                    Log.Write("Writing the reference table...");

                    if (RefTable == null)
                    {
                        w.Write(0);
                    }
                    else
                    {
                        RefTable.Write(w);
                    }

                    w.Write(ms.ToArray(), 0, (int)ms.Length);
                }
        }
示例#3
0
文件: Chunk.cs 项目: jamesrom/gbx-net
        public static uint Remap(uint chunkID, ClassIDRemap remap = ClassIDRemap.Latest)
        {
            var classPart = chunkID & 0xFFFFF000;
            var chunkPart = chunkID & 0xFFF;

            switch (remap)
            {
            case ClassIDRemap.ManiaPlanet:
                if (Node.Mappings.TryGetValue(classPart, out uint newID))
                {
                    return(newID + chunkPart);
                }
                return(chunkID);

            case ClassIDRemap.TrackMania:
                if (classPart == 0x03078000)     // Not ideal solution
                {
                    return(0x24061000 + chunkPart);
                }
                return(Node.Mappings.LastOrDefault(x => x.Value == classPart).Key + chunkPart);

            default:
                return(chunkID);
            }
        }
示例#4
0
        /// <summary>
        /// Saves the serialized <see cref="GameBox{T}"/> to a stream.
        /// </summary>
        /// <param name="stream">Any kind of stream that supports writing.</param>
        /// <param name="remap">What to remap the newest node IDs to. Used for older games.</param>
        public void Save(Stream stream, ClassIDRemap remap)
        {
            if (IntPtr.Size == 8)
            {
                throw new NotSupportedException("Saving GBX is not supported with x64 platform target, due to LZO implementation. Please force your platform target to x86.");
            }

            using (var w = new GameBoxWriter(stream))
                Write(w, remap);
        }
示例#5
0
        public void Write(GameBoxWriter w, ClassIDRemap remap)
        {
            if (GBX.BodyCompression == 'C')
            {
                using (var msBody = new MemoryStream())
                    using (var gbxwBody = new GameBoxWriter(msBody, this))
                    {
                        GBX.MainNode.Write(gbxwBody, remap);
                        MiniLZO.Compress(msBody.ToArray(), out byte[] output);

                        w.Write((int)msBody.Length);       // Uncompressed
                        w.Write(output.Length);            // Compressed
                        w.Write(output, 0, output.Length); // Compressed body data
                    }
            }
            else
            {
                GBX.MainNode.Write(w);
            }

            // ...
        }
示例#6
0
        public void Write(GameBoxWriter w, ClassIDRemap remap)
        {
            var stopwatch = Stopwatch.StartNew();

            int counter = 0;

            foreach (Chunk chunk in Chunks)
            {
                counter++;

                var logChunk = $"[{ClassName}] 0x{chunk.ID:X8} ({(float)counter / Chunks.Count:0.00%})";
                if (Body?.GBX.ClassID.HasValue == true && Remap(Body.GBX.ClassID.Value) == ID)
                {
                    Log.Write(logChunk);
                }
                else
                {
                    Log.Write($"~ {logChunk}");
                }

                ((IChunk)chunk).Node   = this;
                chunk.Unknown.Position = 0;

                ILookbackable lb = chunk.Lookbackable;

                if (chunk is ILookbackable l)
                {
                    l.IdWritten = false;
                    l.IdStrings.Clear();

                    lb = l;
                }

                if (lb == null)
                {
                    if (ParentChunk is ILookbackable l2)
                    {
                        lb = l2;
                    }
                    else
                    {
                        lb = w.Lookbackable;
                    }
                }

                using (var ms = new MemoryStream())
                    using (var msW = new GameBoxWriter(ms, lb))
                    {
                        var rw = new GameBoxReaderWriter(msW);

                        msW.Chunk = chunk;

                        try
                        {
                            if (chunk is ISkippableChunk s && !s.Discovered)
                            {
                                s.Write(msW);
                            }
                            else if (chunk.GetType().GetCustomAttribute <AutoReadWriteChunkAttribute>() == null)
                            {
                                ((IChunk)chunk).ReadWrite(this, rw);
                            }
                            else
                            {
                                msW.Write(chunk.Unknown.ToArray(), 0, (int)chunk.Unknown.Length);
                            }

                            w.Write(Chunk.Remap(chunk.ID, remap));

                            if (chunk is ISkippableChunk)
                            {
                                w.Write(0x534B4950);
                                w.Write((int)ms.Length);
                            }

                            w.Write(ms.ToArray(), 0, (int)ms.Length);
                        }
示例#7
0
        public void Write(GameBoxWriter w, int numNodes, ClassIDRemap remap)
        {
            w.Write(GameBox.Magic, StringLengthPrefix.None);
            w.Write(GBX.Version);

            if (GBX.Version >= 3)
            {
                w.Write((byte)GBX.ByteFormat.GetValueOrDefault());
                w.Write((byte)GBX.RefTableCompression.GetValueOrDefault());
                w.Write((byte)GBX.BodyCompression.GetValueOrDefault());
                if (GBX.Version >= 4)
                {
                    w.Write((byte)GBX.UnknownByte.GetValueOrDefault());
                }
                w.Write(GBX.ClassID.GetValueOrDefault());

                if (GBX.Version >= 6)
                {
                    if (Chunks == null)
                    {
                        w.Write(0);
                    }
                    else
                    {
                        using (var userData = new MemoryStream())
                            using (var gbxw = new GameBoxWriter(userData, this))
                            {
                                var gbxrw = new GameBoxReaderWriter(gbxw);

                                Dictionary <uint, int> lengths = new Dictionary <uint, int>();

                                foreach (var chunk in Chunks)
                                {
                                    chunk.Unknown.Position = 0;

                                    var pos = userData.Position;
                                    if (((ISkippableChunk)chunk).Discovered)
                                    {
                                        ((IChunk)chunk).ReadWrite(((GameBox <T>)GBX).MainNode, gbxrw);
                                    }
                                    else
                                    {
                                        ((ISkippableChunk)chunk).Write(gbxw);
                                    }

                                    lengths[chunk.ID] = (int)(userData.Position - pos);
                                }

                                // Actual data size plus the class id (4 bytes) and each length (4 bytes) plus the number of chunks integer
                                w.Write((int)userData.Length + Chunks.Count * 8 + 4);

                                // Write number of header chunks integer
                                w.Write(Chunks.Count);

                                foreach (Chunk chunk in Chunks)
                                {
                                    w.Write(Chunk.Remap(chunk.ID, remap));
                                    var length = lengths[chunk.ID];
                                    if (((IHeaderChunk)chunk).IsHeavy)
                                    {
                                        length |= 1 << 31;
                                    }
                                    w.Write(length);
                                }

                                w.Write(userData.ToArray(), 0, (int)userData.Length);
                            }
                    }
                }

                w.Write(numNodes);
            }
        }