Bunny83 / SimpleJSON

A simple JSON parser in C#
MIT License
735 stars 294 forks source link

Backwards compatibility #23

Closed cclogg closed 4 years ago

cclogg commented 5 years ago

Hey I was on the 2012 version and just found out about the new updates, but unfortunately my game's level files are made using binary from that version, so they can't load (something error binary type 104). Is there any sort of easy way to up-convert an existing binary JSON file? I would love to use the new improvements.

Thanks.

Bunny83 commented 5 years ago

Well, unfortunately the old format was missing some important things which made it incomplete with the JSON standard. Long story short: The "old" binary format isn't compatible with the new one. Since it doesn't include a version marker (since it only serializes the raw data) the deserializer can't tell them apart. If using this as a save-game solution you should include a version in the binary stream yourself.

About converting the old format into the new: It's currently not implemented since versioning should be done seperately.

Anyways i have quickly created a deserialize method that will read the "old format" for the new classes:

        public static JSONNode DeserializeBinaryOld(System.IO.BinaryReader aReader)
        {
            byte type = aReader.ReadByte();
            switch (type)
            {
                case 1: // old JSONArray
                    {
                        int count = aReader.ReadInt32();
                        JSONArray tmp = new JSONArray();
                        for (int i = 0; i < count; i++)
                            tmp.Add(DeserializeBinaryOld(aReader));
                        return tmp;
                    }
                case 2: // old JSONClass
                    {
                        int count = aReader.ReadInt32();
                        JSONObject tmp = new JSONObject();
                        for (int i = 0; i < count; i++)
                        {
                            string key = aReader.ReadString();
                            var val = DeserializeBinaryOld(aReader);
                            tmp.Add(key, val);
                        }
                        return tmp;
                    }
                case 3: // old JSONData as string
                    {
                        return new JSONString(aReader.ReadString());
                    }
                case 4: // old JSONData as int32
                    {
                        return new JSONNumber(aReader.ReadInt32());
                    }
                case 5: // old JSONData as double
                    {
                        return new JSONNumber(aReader.ReadDouble());
                    }
                case 6: // old JSONData as boolean
                    {
                        return new JSONBool(aReader.ReadBoolean());
                    }
                case 7: // old JSONData as float
                    {
                        return new JSONNumber(aReader.ReadSingle());
                    }
                default:
                    {
                        throw new Exception("Error deserializing old JSON format. Unknown tag: " + type);
                    }
            }
        }

#if USE_SharpZipLib
        public static JSONNode LoadFromCompressedStreamOld(System.IO.Stream aData)
        {
            var zin = new ICSharpCode.SharpZipLib.BZip2.BZip2InputStream(aData);
            return LoadFromBinaryStreamOld(zin);
        }
        public static JSONNode LoadFromCompressedFileOld(string aFileName)
        {
            using(var F = System.IO.File.OpenRead(aFileName))
            {
                return LoadFromCompressedStreamOld(F);
            }
        }
        public static JSONNode LoadFromCompressedBase64Old(string aBase64)
        {
            var tmp = System.Convert.FromBase64String(aBase64);
            var stream = new System.IO.MemoryStream(tmp);
            stream.Position = 0;
            return LoadFromCompressedStreamOld(stream);
        }
#endif

        public static JSONNode LoadFromBinaryStreamOld(System.IO.Stream aData)
        {
            using (var R = new System.IO.BinaryReader(aData))
            {
                return DeserializeBinaryOld(R);
            }
        }

        public static JSONNode LoadFromBinaryFileOld(string aFileName)
        {
            using (var F = System.IO.File.OpenRead(aFileName))
            {
                return LoadFromBinaryStreamOld(F);
            }
        }

So this is just a seperate set of the loading methods with the suffix "Old". You have to handle the choosing of the format yourself. If you get an exception with the new one you may try the old one. Though it would probably be better to implement a seperate conversion method (loading the old format and saving the new).

I had never thought someone actually using the binary format :)

Note: I found a bug in the "SimpleJSONBinary.cs" file when using the compression library. I fixed it on-the-fly without testing. If you find any other issues, feel free to create a new issue here. I do not check the issues regularily but i will keep an eye on this one. If i find the time i'll run some tests myself.

cclogg commented 5 years ago

Haha the binary format was fast so I liked it. Especially because level files are crazy huge. I like the idea of conversion. Maybe what I can do is use that old-load method in my editor to load the file, and then save to the new format after that, like you said. And then after that, just use the new methods for loading/saving.