001package squidpony.store.json;
002
003import com.badlogic.gdx.files.FileHandle;
004import com.badlogic.gdx.utils.Json;
005import com.badlogic.gdx.utils.JsonWriter;
006import com.badlogic.gdx.utils.SerializationException;
007import squidpony.LZSPlus;
008
009import java.io.InputStream;
010import java.io.Reader;
011import java.io.Writer;
012
013/**
014 * A variant of {@link JsonConverter} (and an extension of libGDX's {@link Json} class) that
015 * compresses its JSON output and reads compressed input. Due to limits on the String compression library this uses
016 * (namely, it only compresses Strings, so input must be able to be interpreted as a String), this only allows String
017 * and FileHandle input formats, and throws exceptions if you try to deserialize a char array, InputStream, or Reader
018 * with fromJson() . Otherwise, it acts like JsonConverter, so the same docs apply:
019 * <br>
020 * Augmented version of LibGDX's Json class that knows how to handle various data types common in SquidLib.
021 * This includes OrderedMap, which notably allows non-String keys (LibGDX's default Map serializer requires keys to be
022 * Strings), but does not currently allow the IHasher to be set (which only should affect OrderedMaps with array keys).
023 * It also makes significantly shorter serialized output for 2D char arrays, GreasedRegion and FakeLanguageGen objects,
024 * and various collections (IntDoubleOrderedMap, IntVLA, Arrangement, K2, and K2V1 at least).
025 * Created by Tommy Ettinger on 1/9/2017.
026 */
027public class JsonCompressor extends Json {
028    public JsonCompressor() {
029        super();
030        JsonConverter.initialize(this);
031    }
032
033    public JsonCompressor(JsonWriter.OutputType outputType) {
034        super(outputType);
035        JsonConverter.initialize(this);
036    }
037
038    /**
039     * @param object      The object to serialize
040     * @param knownType   May be null if the type is unknown.
041     * @param elementType May be null if the type is unknown.
042     */
043    @Override
044    public String toJson(Object object, Class knownType, Class elementType) {
045        return LZSPlus.compress(super.toJson(object, knownType, elementType));
046    }
047
048    /**
049     * @param object      The object to serialize
050     * @param knownType   May be null if the type is unknown.
051     * @param elementType May be null if the type is unknown.
052     * @param file        A LibGDX FileHandle that can be written to; overwrites, does not append
053     */
054    @Override
055    public void toJson (Object object, Class knownType, Class elementType, FileHandle file) {
056        try {
057            file.writeString(this.toJson(object, knownType, elementType), false, "UTF-8");
058        } catch (Exception ex) {
059            throw new SerializationException("Error writing file: " + file, ex);
060        }
061    }
062
063    /**
064     * Don't use this, please! This method doesn't compress its output.
065     * @param object      The object to serialize
066     * @param knownType   May be null if the type is unknown.
067     * @param elementType May be null if the type is unknown.
068     * @param writer      A Writer that will be the recipient of this class' JSON output
069     */
070    @Override
071    @Deprecated
072    public void toJson(Object object, Class knownType, Class elementType, Writer writer) {
073        super.toJson(object, knownType, elementType, writer);
074    }
075
076    /**
077     * @param type   May be null if the type is unknown.
078     * @param reader
079     * @return May be null.
080     */
081    @Override
082    public <T> T fromJson(Class<T> type, Reader reader) {
083        throw new UnsupportedOperationException("fromJson() given a char[], Reader or InputStream won't decompress;" +
084                "use the overloads that take a String or FileHandle instead");
085    }
086
087    /**
088     * @param type        May be null if the type is unknown.
089     * @param elementType May be null if the type is unknown.
090     * @param reader
091     * @return May be null.
092     */
093    @Override
094    public <T> T fromJson(Class<T> type, Class elementType, Reader reader) {
095        throw new UnsupportedOperationException("fromJson() given a char[], Reader or InputStream won't decompress;" +
096                "use the overloads that take a String or FileHandle instead");
097    }
098
099    /**
100     * @param type  May be null if the type is unknown.
101     * @param input
102     * @return May be null.
103     */
104    @Override
105    public <T> T fromJson(Class<T> type, InputStream input) {
106        throw new UnsupportedOperationException("fromJson() given a char[], Reader or InputStream won't decompress;" +
107                "use the overloads that take a String or FileHandle instead");
108    }
109
110    /**
111     * @param type        May be null if the type is unknown.
112     * @param elementType May be null if the type is unknown.
113     * @param input
114     * @return May be null.
115     */
116    @Override
117    public <T> T fromJson(Class<T> type, Class elementType, InputStream input) {
118        throw new UnsupportedOperationException("fromJson() given a char[], Reader or InputStream won't decompress;" +
119                "use the overloads that take a String or FileHandle instead");
120    }
121
122    /**
123     * @param type May be null if the type is unknown.
124     * @param file
125     * @return May be null.
126     */
127    @Override
128    public <T> T fromJson(Class<T> type, FileHandle file) {
129        return super.fromJson(type, LZSPlus.decompress(file.readString("UTF-8")));
130    }
131
132    /**
133     * @param type        May be null if the type is unknown.
134     * @param elementType May be null if the type is unknown.
135     * @param file
136     * @return May be null.
137     */
138    @Override
139    public <T> T fromJson(Class<T> type, Class elementType, FileHandle file) {
140        return super.fromJson(type, elementType, LZSPlus.decompress(file.readString("UTF-8")));
141    }
142
143    /**
144     * @param type   May be null if the type is unknown.
145     * @param data
146     * @param offset
147     * @param length
148     * @return May be null.
149     */
150    @Override
151    public <T> T fromJson(Class<T> type, char[] data, int offset, int length) {
152        throw new UnsupportedOperationException("fromJson() given a char[], Reader or InputStream won't decompress;" +
153                "use the overloads that take a String or FileHandle instead");
154    }
155
156    /**
157     * @param type        May be null if the type is unknown.
158     * @param elementType May be null if the type is unknown.
159     * @param data
160     * @param offset
161     * @param length
162     * @return May be null.
163     */
164    @Override
165    public <T> T fromJson(Class<T> type, Class elementType, char[] data, int offset, int length) {
166        throw new UnsupportedOperationException("fromJson() given a char[], Reader or InputStream won't decompress;" +
167                "use the overloads that take a String or FileHandle instead");
168    }
169
170    /**
171     * @param type May be null if the type is unknown.
172     * @param json
173     * @return May be null.
174     */
175    @Override
176    public <T> T fromJson(Class<T> type, String json) {
177        return super.fromJson(type, LZSPlus.decompress(json));
178    }
179
180    /**
181     * @param type        May be null if the type is unknown.
182     * @param elementType
183     * @param json
184     * @return May be null.
185     */
186    @Override
187    public <T> T fromJson(Class<T> type, Class elementType, String json) {
188        return super.fromJson(type, elementType, LZSPlus.decompress(json));
189    }
190}