001/* 002MIT License 003 004Copyright (c) 2018 Tommy Ettinger 005 006Based on lz-string4java, which is: 007Copyright (c) 2016 rufushuang 008 009Permission is hereby granted, free of charge, to any person obtaining a copy 010of this software and associated documentation files (the "Software"), to deal 011in the Software without restriction, including without limitation the rights 012to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 013copies of the Software, and to permit persons to whom the Software is 014furnished to do so, subject to the following conditions: 015 016The above copyright notice and this permission notice shall be included in all 017copies or substantial portions of the Software. 018 019THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 020IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 021FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 022AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 023LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 024OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 025SOFTWARE. 026 */ 027package squidpony; 028 029/** 030 * LZ-String compression, taking Strings and compressing them to other Strings, optionally with some encryption. 031 * This role was performed by the <a href="https://github.com/tommyettinger/BlazingChain">BlazingChain library</a>, 032 * which was a dependency of squidlib-extra, but recent developments have allowed all dependencies to be removed other 033 * than SquidLib, while also probably reducing memory usage by a fair amount. The actual implementation of this class is 034 * very unusual, with the LZ-String encoding part derived from 035 * <a href="https://github.com/rufushuang/lz-string4java">rufushuang's lz-string4java</a> (which is a port of 036 * <a href="https://github.com/pieroxy/lz-string">pieroxy's lz-string</a>), while the encryption-like part (which is not 037 * very strong) was added in SquidLib. This uses {@link Garbler} to do the encryption and {@link LZSEncoding} to do the 038 * compression; LZSEncoding uses the original JavaScript lz-string library almost verbatim when run on GWT, so it 039 * performs better than code that has been compiled to JavaScript from Java by GWT, and it performs like Java when run 040 * on a real JVM. 041 * <br> 042 * Created by Tommy Ettinger on 7/13/2017. 043 */ 044public final class LZSPlus { 045 046 /** 047 * Compresses the given text using LZ-String compression; does not encrypt the result. 048 * @param uncompressedStr text to compress 049 * @return a compressed version of the given text 050 */ 051 public static String compress(String uncompressedStr) { 052 return LZSEncoding.compressToUTF16(uncompressedStr); 053 } 054 055 /** 056 * Compresses the given text using LZ-String compression and encrypts (somewhat) the compressed result so it can't 057 * be read back without the same keys as a long array. Shorter long arrays give less security to encryption, though 058 * there isn't much security to begin with. You can produce a decent-quality array for this purpose with 059 * {@link Garbler#makeKeyArray(int, String)}; the size parameter could reasonably be anywhere from 2 to 32. If the 060 * keys array is null or empty, this only compresses and does not perform an additional encryption step. 061 * @param uncompressedStr text to compress and optionally encrypt 062 * @param keys the long array that will be used to encrypt the output, and will be required to decrypt the result; may be null 063 * @return a compressed and optionally encrypted version of the given text 064 */ 065 public static String compress(String uncompressedStr, long[] keys) { 066 if(keys == null) return LZSEncoding.compressToUTF16(uncompressedStr); 067 if (uncompressedStr == null) return null; 068 if (uncompressedStr.isEmpty()) return " "; 069 return Garbler.garble(LZSEncoding.compressToUTF16(uncompressedStr), keys); 070 } 071 /** 072 * Decompresses text that was compressed with LZ-String compression; does not reverse decryption so it can only 073 * decompress Strings produced by {@link #compress(String)}, or {@link #compress(String, long[])} with an empty or 074 * null keys parameter. 075 * @param compressed text that was compressed by {@link #compress(String)} 076 * @return the original text, decompressed from the given text 077 */ 078 079 public static String decompress(String compressed) { 080 return LZSEncoding.decompressFromUTF16(compressed); 081 } 082 083 /** 084 * Decompresses text that was compressed with LZ-String compression, reversing any encryption if the keys long array 085 * matches the long array passed to {@link #compress(String, long[])} (keys can be null if no array was passed). 086 * @param compressed text that was compressed by {@link #compress(String, long[])} 087 * @param keys the long array that was used to encrypt the output, and must match to decrypt the result; may be null 088 * @return the original text, decompressed and decrypted from compressed 089 */ 090 public static String decompress(String compressed, long[] keys) { 091 if(keys == null) return LZSEncoding.decompressFromUTF16(compressed); 092 if (compressed == null) return null; 093 if (compressed.isEmpty()) return ""; 094 return LZSEncoding.decompressFromUTF16(Garbler.degarble(compressed, keys)); 095 } 096}