From 9b6872b6e52e28b1b99aa328c2109436de58622f Mon Sep 17 00:00:00 2001 From: Douglas Crockford Date: Fri, 6 Feb 2015 09:02:41 -0800 Subject: [PATCH] This package needs a new owner. --- Kim.java | 372 ------------------------------ README | 7 +- zip/BitInputStream.java | 153 ------------- zip/BitOutputStream.java | 154 ------------- zip/BitReader.java | 42 ---- zip/BitWriter.java | 45 ---- zip/Huff.java | 404 -------------------------------- zip/JSONzip.java | 255 --------------------- zip/Keep.java | 191 ---------------- zip/None.java | 15 -- zip/PostMortem.java | 47 ---- zip/README | 2 - zip/Unzipper.java | 310 ------------------------- zip/Zipper.java | 481 --------------------------------------- 14 files changed, 6 insertions(+), 2472 deletions(-) delete mode 100644 Kim.java delete mode 100644 zip/BitInputStream.java delete mode 100644 zip/BitOutputStream.java delete mode 100644 zip/BitReader.java delete mode 100644 zip/BitWriter.java delete mode 100644 zip/Huff.java delete mode 100644 zip/JSONzip.java delete mode 100644 zip/Keep.java delete mode 100644 zip/None.java delete mode 100644 zip/PostMortem.java delete mode 100644 zip/README delete mode 100644 zip/Unzipper.java delete mode 100644 zip/Zipper.java diff --git a/Kim.java b/Kim.java deleted file mode 100644 index 9f7af92..0000000 --- a/Kim.java +++ /dev/null @@ -1,372 +0,0 @@ -package org.json; - - -/* - Copyright (c) 2013 JSON.org - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all - copies or substantial portions of the Software. - - The Software shall be used for Good, not Evil. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. - */ - -/** - * Kim makes immutable eight bit Unicode strings. If the MSB of a byte is set, - * then the next byte is a continuation byte. The last byte of a character - * never has the MSB reset. Every byte that is not the last byte has the MSB - * set. Kim stands for "Keep it minimal". A Unicode character is never longer - * than 3 bytes. Every byte contributes 7 bits to the character. ASCII is - * unmodified. - * - * Kim UTF-8 - * one byte U+007F U+007F - * two bytes U+3FFF U+07FF - * three bytes U+10FFF U+FFFF - * four bytes U+10FFFF - * - * Characters in the ranges U+0800..U+3FFF and U+10000..U+10FFFF will be one - * byte smaller when encoded in Kim compared to UTF-8. - * - * Kim is beneficial when using scripts such as Old South Arabian, Aramaic, - * Avestan, Balinese, Batak, Bopomofo, Buginese, Buhid, Carian, Cherokee, - * Coptic, Cyrillic, Deseret, Egyptian Hieroglyphs, Ethiopic, Georgian, - * Glagolitic, Gothic, Hangul Jamo, Hanunoo, Hiragana, Kanbun, Kaithi, - * Kannada, Katakana, Kharoshthi, Khmer, Lao, Lepcha, Limbu, Lycian, Lydian, - * Malayalam, Mandaic, Meroitic, Miao, Mongolian, Myanmar, New Tai Lue, - * Ol Chiki, Old Turkic, Oriya, Osmanya, Pahlavi, Parthian, Phags-Pa, - * Phoenician, Samaritan, Sharada, Sinhala, Sora Sompeng, Tagalog, Tagbanwa, - * Takri, Tai Le, Tai Tham, Tamil, Telugu, Thai, Tibetan, Tifinagh, UCAS. - * - * A kim object can be constructed from an ordinary UTF-16 string, or from a - * byte array. A kim object can produce a UTF-16 string. - * - * As with UTF-8, it is possible to detect character boundaries within a byte - * sequence. UTF-8 is one of the world's great inventions. While Kim is more - * efficient, it is not clear that it is worth the expense of transition. - * - * @version 2013-04-18 - */ -public class Kim { - - /** - * The byte array containing the kim's content. - */ - private byte[] bytes = null; - - /** - * The kim's hashcode, conforming to Java's hashcode conventions. - */ - private int hashcode = 0; - - /** - * The number of bytes in the kim. The number of bytes can be as much as - * three times the number of characters. - */ - public int length = 0; - - /** - * The memoization of toString(). - */ - private String string = null; - - /** - * Make a kim from a portion of a byte array. - * - * @param bytes - * A byte array. - * @param from - * The index of the first byte. - * @param thru - * The index of the last byte plus one. - */ - public Kim(byte[] bytes, int from, int thru) { - -// As the bytes are copied into the new kim, a hashcode is computed using a -// modified Fletcher code. - - int sum = 1; - int value; - this.hashcode = 0; - this.length = thru - from; - if (this.length > 0) { - this.bytes = new byte[this.length]; - for (int at = 0; at < this.length; at += 1) { - value = (int) bytes[at + from] & 0xFF; - sum += value; - this.hashcode += sum; - this.bytes[at] = (byte) value; - } - this.hashcode += sum << 16; - } - } - - /** - * Make a kim from a byte array. - * - * @param bytes - * The byte array. - * @param length - * The number of bytes. - */ - public Kim(byte[] bytes, int length) { - this(bytes, 0, length); - } - - /** - * Make a new kim from a substring of an existing kim. The coordinates are - * in byte units, not character units. - * - * @param kim - * The source of bytes. - * @param from - * The point at which to take bytes. - * @param thru - * The point at which to stop taking bytes. - */ - public Kim(Kim kim, int from, int thru) { - this(kim.bytes, from, thru); - } - - /** - * Make a kim from a string. - * - * @param string - * The string. - * @throws JSONException - * if surrogate pair mismatch. - */ - public Kim(String string) throws JSONException { - int stringLength = string.length(); - this.hashcode = 0; - this.length = 0; - -// First pass: Determine the length of the kim, allowing for the UTF-16 -// to UTF-32 conversion, and then the UTF-32 to Kim conversion. - - if (stringLength > 0) { - for (int i = 0; i < stringLength; i += 1) { - int c = string.charAt(i); - if (c <= 0x7F) { - this.length += 1; - } else if (c <= 0x3FFF) { - this.length += 2; - } else { - if (c >= 0xD800 && c <= 0xDFFF) { - i += 1; - int d = string.charAt(i); - if (c > 0xDBFF || d < 0xDC00 || d > 0xDFFF) { - throw new JSONException("Bad UTF16"); - } - } - this.length += 3; - } - } - -// Second pass: Allocate a byte array and fill that array with the conversion -// while computing the hashcode. - - this.bytes = new byte[length]; - int at = 0; - int b; - int sum = 1; - for (int i = 0; i < stringLength; i += 1) { - int character = string.charAt(i); - if (character <= 0x7F) { - bytes[at] = (byte) character; - sum += character; - this.hashcode += sum; - at += 1; - } else if (character <= 0x3FFF) { - b = 0x80 | (character >>> 7); - bytes[at] = (byte) b; - sum += b; - this.hashcode += sum; - at += 1; - b = character & 0x7F; - bytes[at] = (byte) b; - sum += b; - this.hashcode += sum; - at += 1; - } else { - if (character >= 0xD800 && character <= 0xDBFF) { - i += 1; - character = (((character & 0x3FF) << 10) | (string - .charAt(i) & 0x3FF)) + 65536; - } - b = 0x80 | (character >>> 14); - bytes[at] = (byte) b; - sum += b; - this.hashcode += sum; - at += 1; - b = 0x80 | ((character >>> 7) & 0xFF); - bytes[at] = (byte) b; - sum += b; - this.hashcode += sum; - at += 1; - b = character & 0x7F; - bytes[at] = (byte) b; - sum += b; - this.hashcode += sum; - at += 1; - } - } - this.hashcode += sum << 16; - } - } - - /** - * Returns the character at the specified index. The index refers to byte - * values and ranges from 0 to length - 1. The index of the next character - * is at index + Kim.characterSize(kim.characterAt(index)). - * - * @param at - * the index of the char value. The first character is at 0. - * @returns a Unicode character between 0 and 0x10FFFF. - * @throws JSONException - * if at does not point to a valid character. - */ - public int characterAt(int at) throws JSONException { - int c = get(at); - if ((c & 0x80) == 0) { - return c; - } - int character; - int c1 = get(at + 1); - if ((c1 & 0x80) == 0) { - character = ((c & 0x7F) << 7) | c1; - if (character > 0x7F) { - return character; - } - } else { - int c2 = get(at + 2); - character = ((c & 0x7F) << 14) | ((c1 & 0x7F) << 7) | c2; - if ((c2 & 0x80) == 0 && character > 0x3FFF && character <= 0x10FFFF - && (character < 0xD800 || character > 0xDFFF)) { - return character; - } - } - throw new JSONException("Bad character at " + at); - } - - /** - * Returns the number of bytes needed to contain the character in Kim - * format. - * - * @param character - * a Unicode character between 0 and 0x10FFFF. - * @return 1, 2, or 3 - * @throws JSONException - * if the character is not representable in a kim. - */ - public static int characterSize(int character) throws JSONException { - if (character < 0 || character > 0x10FFFF) { - throw new JSONException("Bad character " + character); - } - return character <= 0x7F ? 1 : character <= 0x3FFF ? 2 : 3; - } - - /** - * Copy the contents of this kim to a byte array. - * - * @param bytes - * A byte array of sufficient size. - * @param at - * The position within the byte array to take the byes. - * @return The position immediately after the copy. - */ - public int copy(byte[] bytes, int at) { - System.arraycopy(this.bytes, 0, bytes, at, this.length); - return at + this.length; - } - - /** - * Two kim objects containing exactly the same bytes in the same order are - * equal to each other. - * - * @param obj - * the other kim with which to compare. - * @returns true if this and obj are both kim objects containing identical - * byte sequences. - */ - public boolean equals(Object obj) { - if (!(obj instanceof Kim)) { - return false; - } - Kim that = (Kim) obj; - if (this == that) { - return true; - } - if (this.hashcode != that.hashcode) { - return false; - } - return java.util.Arrays.equals(this.bytes, that.bytes); - } - - /** - * Get a byte from a kim. - * @param at - * The position of the byte. The first byte is at 0. - * @return The byte. - * @throws JSONException - * if there is no byte at that position. - */ - public int get(int at) throws JSONException { - if (at < 0 || at > this.length) { - throw new JSONException("Bad character at " + at); - } - return ((int) this.bytes[at]) & 0xFF; - } - - /** - * Returns a hash code value for the kim. - */ - public int hashCode() { - return this.hashcode; - } - - /** - * Produce a UTF-16 String from this kim. The number of codepoints in the - * string will not be greater than the number of bytes in the kim, although - * it could be less. - * - * @return The string. A kim memoizes its string representation. - * @throws JSONException - * if the kim is not valid. - */ - public String toString() throws JSONException { - if (this.string == null) { - int c; - int length = 0; - char chars[] = new char[this.length]; - for (int at = 0; at < this.length; at += characterSize(c)) { - c = this.characterAt(at); - if (c < 0x10000) { - chars[length] = (char) c; - length += 1; - } else { - chars[length] = (char) (0xD800 | ((c - 0x10000) >>> 10)); - length += 1; - chars[length] = (char) (0xDC00 | (c & 0x03FF)); - length += 1; - } - } - this.string = new String(chars, 0, length); - } - return this.string; - } -} diff --git a/README b/README index 6afe0c6..2de22ff 100755 --- a/README +++ b/README @@ -1,9 +1,14 @@ JSON in Java [package org.json] +This package needs a new owner. I have not used it in over a decade, and I do +not have time to maintain programs that I do not use. + +If you think you can give this package a good home, please contact me. + Douglas Crockford douglas@crockford.com -2011-02-02 +2015-02-06 JSON is a light-weight, language independent, data interchange format. diff --git a/zip/BitInputStream.java b/zip/BitInputStream.java deleted file mode 100644 index 2282d30..0000000 --- a/zip/BitInputStream.java +++ /dev/null @@ -1,153 +0,0 @@ -package org.json.zip; - -import java.io.IOException; -import java.io.InputStream; - -/* - Copyright (c) 2013 JSON.org - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all - copies or substantial portions of the Software. - - The Software shall be used for Good, not Evil. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. - */ - -/** - * This is a big endian bit reader. It reads its bits from an InputStream. - * - * @version 2013-05-03 - * - */ -public class BitInputStream implements BitReader { - /** - * The number of bits remaining in the current byte. - */ - private int available = 0; - - /** - * Up to a byte's worth of unread bits. - */ - private int unread = 0; - - /** - * The source of the bits. - */ - private InputStream in; - - /** - * The number of bits read so far. This is used in padding. - */ - private long nrBits = 0; - - /** - * Make a BitReader from an InputStream. The BitReader will take bytes from - * the InputStream and unpack them into bits. - * - * @param in - * An InputStream. - */ - public BitInputStream(InputStream in) { - this.in = in; - } - - /** - * Read one bit. - * - * @return true if it is a 1 bit. - */ - public boolean bit() throws IOException { - return read(1) != 0; - } - - /** - * Get the number of bits that have been read from this BitInputStream. - * This includes pad bits that have been skipped, but might not include - * bytes that have been read from the underlying InputStream that have not - * yet been delivered as bits. - * - * @return The number of bits read so far. - */ - public long nrBits() { - return this.nrBits; - } - - /** - * Check that the rest of the block has been padded with zeroes. - * - * @param width - * The size of the block to pad in bits. - * This will typically be 8, 16, 32, 64, 128, 256, etc. - * @return true if the block was zero padded, or false if the the padding - * contains any one bits. - * @throws IOException - */ - public boolean pad(int width) throws IOException { - boolean result = true; - int gap = (int)this.nrBits % width; - if (gap < 0) { - gap += width; - } - if (gap != 0) { - int padding = width - gap; - while (padding > 0) { - if (bit()) { - result = false; - } - padding -= 1; - } - } - return result; - } - - /** - * Read some bits. - * - * @param width - * The number of bits to read. (0..32) - * @throws IOException - * @return the bits - */ - public int read(int width) throws IOException { - if (width == 0) { - return 0; - } - if (width < 0 || width > 32) { - throw new IOException("Bad read width."); - } - int result = 0; - while (width > 0) { - if (this.available == 0) { - this.unread = this.in.read(); - if (this.unread < 0) { - throw new IOException("Attempt to read past end."); - } - this.available = 8; - } - int take = width; - if (take > this.available) { - take = this.available; - } - result |= ((this.unread >>> (this.available - take)) & - ((1 << take) - 1)) << (width - take); - this.nrBits += take; - this.available -= take; - width -= take; - } - return result; - } -} diff --git a/zip/BitOutputStream.java b/zip/BitOutputStream.java deleted file mode 100644 index da47301..0000000 --- a/zip/BitOutputStream.java +++ /dev/null @@ -1,154 +0,0 @@ -package org.json.zip; - -import java.io.IOException; -import java.io.OutputStream; - -/* - Copyright (c) 2013 JSON.org - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all - copies or substantial portions of the Software. - - The Software shall be used for Good, not Evil. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. - */ - -/** - * This is a big endian bit writer. It writes its bits to an OutputStream. - * - * @version 2013-05-03 - * - */ -public class BitOutputStream implements BitWriter { - - /** - * The number of bits written. - */ - private long nrBits = 0; - - /** - * The destination of the bits. - */ - private OutputStream out; - - /** - * Holder of bits not yet written. - */ - private int unwritten; - - /** - * The number of unused bits in this.unwritten. - */ - private int vacant = 8; - - /** - * Use an OutputStream to produce a BitWriter. The BitWriter will send its - * bits to the OutputStream as each byte is filled. - * - * @param out - * An Output Stream - */ - public BitOutputStream(OutputStream out) { - this.out = out; - } - - /** - * Returns the number of bits that have been written to this - * bitOutputStream. This may include bits that have not yet been written - * to the underlying outputStream. - */ - public long nrBits() { - return this.nrBits; - } - - /** - * Write a 1 bit. - * - * @throws IOException - */ - public void one() throws IOException { - write(1, 1); - } - - /** - * Pad the rest of the block with zeros and flush. pad(8) flushes the last - * unfinished byte. The underlying OutputStream will be flushed. - * - * @param width - * The size of the block to pad in bits. - * This will typically be 8, 16, 32, 64, 128, 256, etc. - * @throws IOException - */ - public void pad(int width) throws IOException { - int gap = (int)this.nrBits % width; - if (gap < 0) { - gap += width; - } - if (gap != 0) { - int padding = width - gap; - while (padding > 0) { - this.zero(); - padding -= 1; - } - } - this.out.flush(); - } - - /** - * Write some bits. Up to 32 bits can be written at a time. - * - * @param bits - * The bits to be written. - * @param width - * The number of bits to write. (0..32) - * @throws IOException - */ - public void write(int bits, int width) throws IOException { - if (bits == 0 && width == 0) { - return; - } - if (width <= 0 || width > 32) { - throw new IOException("Bad write width."); - } - while (width > 0) { - int actual = width; - if (actual > this.vacant) { - actual = this.vacant; - } - this.unwritten |= ((bits >>> (width - actual)) & - ((1 << actual) - 1)) << (this.vacant - actual); - width -= actual; - nrBits += actual; - this.vacant -= actual; - if (this.vacant == 0) { - this.out.write(this.unwritten); - this.unwritten = 0; - this.vacant = 8; - } - } - } - - /** - * Write a 0 bit. - * - * @throws IOException - */ - public void zero() throws IOException { - write(0, 1); - - } -} diff --git a/zip/BitReader.java b/zip/BitReader.java deleted file mode 100644 index 4fd99db..0000000 --- a/zip/BitReader.java +++ /dev/null @@ -1,42 +0,0 @@ -package org.json.zip; - -import java.io.IOException; - -public interface BitReader { - - /** - * Read one bit. - * - * @return true if it is a 1 bit. - */ - public boolean bit() throws IOException; - - /** - * Returns the number of bits that have been read from this bitreader. - * - * @return The number of bits read so far. - */ - public long nrBits(); - - /** - * Check that the rest of the block has been padded with zeros. - * - * @param width - * The size in bits of the block to pad. This will typically be - * 8, 16, 32, 64, 128, 256, etc. - * @return true if the block was zero padded, or false if the the padding - * contained any one bits. - * @throws IOException - */ - public boolean pad(int width) throws IOException; - - /** - * Read some bits. - * - * @param width - * The number of bits to read. (0..32) - * @throws IOException - * @return the bits - */ - public int read(int width) throws IOException; -} diff --git a/zip/BitWriter.java b/zip/BitWriter.java deleted file mode 100644 index ba8a109..0000000 --- a/zip/BitWriter.java +++ /dev/null @@ -1,45 +0,0 @@ -package org.json.zip; - -import java.io.IOException; - -/** - * A bitwriter is a an interface that allows for doing output at the bit level. - * Most IO interfaces only allow for writing at the byte level or higher. - */ -public interface BitWriter { - - /** - * Write a 1 bit. - * - * @throws IOException - */ - public void one() throws IOException; - - /** - * Pad the rest of the block with zeros and flush. - * - * @param width - * The size in bits of the block to pad. This will typically be - * 8, 16, 32, 64, 128, 256, etc. - * @throws IOException - */ - public void pad(int width) throws IOException; - - /** - * Write some bits. Up to 32 bits can be written at a time. - * - * @param bits - * The bits to be written. - * @param width - * The number of bits to write. (0..32) - * @throws IOException - */ - public void write(int bits, int width) throws IOException; - - /** - * Write a 0 bit. - * - * @throws IOException - */ - public void zero() throws IOException; -} diff --git a/zip/Huff.java b/zip/Huff.java deleted file mode 100644 index a7849ae..0000000 --- a/zip/Huff.java +++ /dev/null @@ -1,404 +0,0 @@ -package org.json.zip; - -import org.json.JSONException; - -/* - Copyright (c) 2013 JSON.org - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all - copies or substantial portions of the Software. - - The Software shall be used for Good, not Evil. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. - */ - -/** - * JSONzip is a compression scheme for JSON text. - * @author JSON.org - * @version 2014-05-20 - */ - -/** - * A Huffman encoder/decoder. It operates over a domain of integers, which may - * map to characters or other symbols. Symbols that are used frequently are - * given shorter codes than symbols that are used infrequently. This usually - * produces shorter messages. - * - * Initially, all of the symbols are given the same weight. The weight of a - * symbol is incremented by the tick method. The generate method is used to - * generate the encoding table. The table must be generated before encoding or - * decoding. You may regenerate the table with the latest weights at any time. - * - * After a million ticks, it is assumed that the distribution is well - * understood and that no more regeneration will be required. - */ -public class Huff implements None, PostMortem { - - /** - * The number of symbols known to the encoder. - */ - private final int domain; - - /** - * The number of characters to process before generation is no longer done. - */ - public static final int education = 1000000; - - /** - * An array that maps symbol values to symbols. - */ - private final Symbol[] symbols; - - /** - * The root of the decoding table, and the terminal of the encoding table. - */ - private Symbol table; - - /** - * The number of characters left to learn to adapt the coding table. - */ - private int toLearn; - - /** - * Have any weights changed since the table was last generated? - */ - private boolean upToDate = false; - - /** - * The number of bits in the last symbol. This is used in tracing. - */ - private int width; - - private static class Symbol implements PostMortem { - public Symbol back; - public Symbol next; - public Symbol zero; - public Symbol one; - public final int integer; - public long weight; - - /** - * Make a symbol representing a character or other value. - * - * @param integer - * The symbol's number - */ - public Symbol(int integer) { - this.integer = integer; - this.weight = 0; - this.next = null; - this.back = null; - this.one = null; - this.zero = null; - } - - public boolean postMortem(PostMortem pm) { - boolean result = true; - Symbol that = (Symbol) pm; - - if (this.integer != that.integer || this.weight != that.weight) { - return false; - } - if ((this.back == null) != (that.back == null)) { - return false; - } - Symbol zero = this.zero; - Symbol one = this.one; - if (zero == null) { - if (that.zero != null) { - return false; - } - } else { - result = zero.postMortem(that.zero); - } - if (one == null) { - if (that.one != null) { - return false; - } - } else { - result = one.postMortem(that.one); - } - return result; - } - - } - - /** - * Construct a Huffman encoder/decoder. - * - * @param domain - * The number of values known to the object. - */ - public Huff(int domain) { - this.domain = domain; - this.toLearn = education; - int length = domain * 2 - 1; - this.symbols = new Symbol[length]; - -// Make the leaf symbols. - - for (int i = 0; i < domain; i += 1) { - symbols[i] = new Symbol(i); - } - -// Make the links. - - for (int i = domain; i < length; i += 1) { - symbols[i] = new Symbol(none); - } - } - - /** - * Generate the encoding/decoding table. The table determines the bit - * sequences used by the read and write methods. - */ - public void generate() { - if (!this.upToDate) { - -// Phase One: Sort the symbols by weight into a linked list. - - Symbol head = this.symbols[0]; - Symbol next; - Symbol previous = head; - Symbol symbol; - - this.table = null; - head.next = null; - for (int i = 1; i < this.domain; i += 1) { - symbol = symbols[i]; - -// If this symbol weights less than the head, then it becomes the new head. - - if (symbol.weight < head.weight) { - symbol.next = head; - head = symbol; - } else { - -// We will start the search from the previous symbol instead of the head unless -// the current symbol weights less than the previous symbol. - - if (symbol.weight < previous.weight) { - previous = head; - } - -// Find a connected pair (previous and next) where the symbol weighs the same -// or more than previous but less than the next. Link the symbol between them. - - while (true) { - next = previous.next; - if (next == null || symbol.weight < next.weight) { - break; - } - previous = next; - } - symbol.next = next; - previous.next = symbol; - previous = symbol; - } - } - -// Phase Two: Make new symbols from the two lightest symbols until only one -// symbol remains. The final symbol becomes the root of the table binary tree. - - int avail = this.domain; - Symbol first; - Symbol second; - previous = head; - while (true) { - first = head; - second = first.next; - head = second.next; - symbol = this.symbols[avail]; - avail += 1; - symbol.weight = first.weight + second.weight; - symbol.zero = first; - symbol.one = second; - symbol.back = null; - first.back = symbol; - second.back = symbol; - if (head == null) { - break; - } - -// Insert the new symbol back into the sorted list. - - if (symbol.weight < head.weight) { - symbol.next = head; - head = symbol; - previous = head; - } else { - while (true) { - next = previous.next; - if (next == null || symbol.weight < next.weight) { - break; - } - previous = next; - } - symbol.next = next; - previous.next = symbol; - previous = symbol; - } - - } - -// The last remaining symbol is the root of the table. - - this.table = symbol; - this.upToDate = true; - } - } - - private boolean postMortem(int integer) { - int[] bits = new int[this.domain]; - Symbol symbol = this.symbols[integer]; - if (symbol.integer != integer) { - return false; - } - int i = 0; - while (true) { - Symbol back = symbol.back; - if (back == null) { - break; - } - if (back.zero == symbol) { - bits[i] = 0; - } else if (back.one == symbol) { - bits[i] = 1; - } else { - return false; - } - i += 1; - symbol = back; - } - if (symbol != this.table) { - return false; - } - this.width = 0; - symbol = this.table; - while (symbol.integer == none) { - i -= 1; - symbol = bits[i] != 0 ? symbol.one : symbol.zero; - } - return symbol.integer == integer && i == 0; - } - - /** - * Compare two Huffman tables. - */ - public boolean postMortem(PostMortem pm) { - -// Go through every integer in the domain, generating its bit sequence, and -// then prove that that bit sequence produces the same integer. - - for (int integer = 0; integer < this.domain; integer += 1) { - if (!postMortem(integer)) { - JSONzip.log("\nBad huff "); - JSONzip.logchar(integer, integer); - return false; - } - } - return this.table.postMortem(((Huff) pm).table); - } - - /** - * Read bits until a symbol can be identified. The weight of the read - * symbol will be incremented. - * - * @param bitreader - * The source of bits. - * @return The integer value of the symbol. - * @throws JSONException - */ - public int read(BitReader bitreader) throws JSONException { - try { - this.width = 0; - Symbol symbol = this.table; - while (symbol.integer == none) { - this.width += 1; - symbol = bitreader.bit() ? symbol.one : symbol.zero; - } - tick(symbol.integer); - if (JSONzip.probe) { - JSONzip.logchar(symbol.integer, this.width); - } - return symbol.integer; - } catch (Throwable e) { - throw new JSONException(e); - } - } - - /** - * Increase the weight associated with a value by 1. - * - * @param value - * The number of the symbol to tick - */ - public void tick(int value) { - if (this.toLearn > 0) { - this.toLearn -= 1; - this.symbols[value].weight += 1; - this.upToDate = false; - } - } - - /** - * Recur from a symbol back, emitting bits. We recur before emitting to - * make the bits come out in the right order. - * - * @param symbol - * The symbol to write. - * @param bitwriter - * The bitwriter to write it to. - * @throws JSONException - */ - private void write(Symbol symbol, BitWriter bitwriter) - throws JSONException { - try { - Symbol back = symbol.back; - if (back != null) { - this.width += 1; - write(back, bitwriter); - if (back.zero == symbol) { - bitwriter.zero(); - } else { - bitwriter.one(); - } - } - } catch (Throwable e) { - throw new JSONException(e); - } - } - - /** - * Write the bits corresponding to a symbol. The weight of the symbol will - * be incremented. - * - * @param value - * The number of the symbol to write - * @param bitwriter - * The destination of the bits. - * @throws JSONException - */ - public void write(int value, BitWriter bitwriter) throws JSONException { - this.width = 0; - write(this.symbols[value], bitwriter); - tick(value); - if (JSONzip.probe) { - JSONzip.logchar(value, this.width); - } - } -} diff --git a/zip/JSONzip.java b/zip/JSONzip.java deleted file mode 100644 index d8e3ac6..0000000 --- a/zip/JSONzip.java +++ /dev/null @@ -1,255 +0,0 @@ -package org.json.zip; - -/* - Copyright (c) 2013 JSON.org - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all - copies or substantial portions of the Software. - - The Software shall be used for Good, not Evil. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. - */ - -/** - * JSONzip is a binary-encoded JSON dialect. It is designed to compress the - * messages in a session in bandwidth constrained applications, such as mobile. - * - * JSONzip is adaptive, so with each message seen, it should improve its - * compression. It minimizes JSON's overhead, reducing punctuation - * to a small number of bits. It uses Huffman encoding to reduce the average - * size of characters. It uses caches (or Keeps) to keep recently seen strings - * and values, so repetitive content (such as object keys) can be - * substantially reduced. It uses a character encoding called Kim (Keep it - * minimal) that is smaller than UTF-8 for most East European, African, and - * Asian scripts. - * - * JSONzip tends to reduce most content by about half. If there is a lot of - * recurring information, the reduction can be much more dramatic. - * - * FOR EVALUATION PURPOSES ONLY. THIS PACKAGE HAS NOT YET BEEN TESTED - * ADEQUATELY FOR PRODUCTION USE. - * - * @author JSON.org - * @version 2014-05-20 - */ -public abstract class JSONzip implements None, PostMortem { - /** - * The characters in JSON numbers can be reduced to 4 bits each. - */ - public static final byte[] bcd = { - '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '.', '-', '+', 'E' - }; - - /** - * The end of string code. - */ - public static final int end = 256; - - /** - * The end of number code. - */ - public static final int endOfNumber = bcd.length; - - /** - * The first positive integer that cannot be encoded in 4 bits. - */ - public static final long int4 = 16; - - /** - * The first positive integer that cannot be encoded in 7 bits. - */ - public static final long int7 = 144; - - /** - * The first positive integer that cannot be encoded in 14 bits. - */ - public static final long int14 = 16528; - - /** - * The package supports tracing for debugging. - */ - public static final boolean probe = false; - - /** - * The value code for an empty object. - */ - public static final int zipEmptyObject = 0; - - /** - * The value code for an empty array. - */ - public static final int zipEmptyArray = 1; - - /** - * The value code for true. - */ - public static final int zipTrue = 2; - - /** - * The value code for false. - */ - public static final int zipFalse = 3; - - /** - * The value code for null. - */ - public static final int zipNull = 4; - - /** - * The value code for a non-empty object. - */ - public static final int zipObject = 5; - - /** - * The value code for an array with a string as its first element. - */ - public static final int zipArrayString = 6; - - /** - * The value code for an array with a non-string value as its first element. - */ - public static final int zipArrayValue = 7; - - /** - * A Huffman encoder for names. - */ - protected final Huff namehuff; - - /** - * A Huffman encoder for names extended bytes. - */ - protected final Huff namehuffext; - - /** - * A place to keep the names (keys). - */ - protected final Keep namekeep; - - /** - * A Huffman encoder for string values. - */ - protected final Huff stringhuff; - - /** - * A Huffman encoder for string values extended bytes. - */ - protected final Huff stringhuffext; - - /** - * A place to keep the strings. - */ - protected final Keep stringkeep; - - /** - * A place to keep the values. - */ - protected final Keep valuekeep; - - /** - * Initialize the data structures. - */ - protected JSONzip() { - this.namehuff = new Huff(end + 1); - this.namehuffext = new Huff(end + 1); - this.namekeep = new Keep(9); - this.stringhuff = new Huff(end + 1); - this.stringhuffext = new Huff(end + 1); - this.stringkeep = new Keep(11); - this.valuekeep = new Keep(10); - } - - /** - * Generate the Huffman tables. - */ - protected void generate() { - this.namehuff.generate(); - this.namehuffext.generate(); - this.stringhuff.generate(); - this.stringhuffext.generate(); - } - - /** - * Write an end-of-line to the console. - */ - static void log() { - log("\n"); - } - - /** - * Write an integer to the console. - * - * @param integer The integer to write to the log. - */ - static void log(int integer) { - log(integer + " "); - } - - /** - * Write two integers, separated by ':' to the console. - * The second integer is suppressed if it is 1. - * - * @param integer The integer to write to the log. - * @param width The width of the integer in bits. - */ - static void log(int integer, int width) { - if (width == 1) { - log(integer); - } else { - log(integer + ":" + width + " "); - } - } - - /** - * Write a string to the console. - * - * @param string The string to be written to the log. - */ - static void log(String string) { - System.out.print(string); - } - - /** - * Write a character or its code to the console. - * - * @param integer The charcode to be written to the log. - * @param width The width of the charcode in bits. - */ - static void logchar(int integer, int width) { - if (integer > ' ' && integer <= '}') { - log("'" + (char) integer + "':" + width + " "); - } else { - log(integer, width); - } - } - - /** - * This method is used for testing the implementation of JSONzip. It is not - * suitable for any other purpose. It is used to compare a Compressor and a - * Decompressor, verifying that the data structures that were built during - * zipping and unzipping were the same. - * - * @return true if the structures match. - */ - public boolean postMortem(PostMortem pm) { - JSONzip that = (JSONzip) pm; - return this.namehuff.postMortem(that.namehuff) - && this.namekeep.postMortem(that.namekeep) - && this.stringkeep.postMortem(that.stringkeep) - && this.stringhuff.postMortem(that.stringhuff) - && this.valuekeep.postMortem(that.valuekeep); - } -} diff --git a/zip/Keep.java b/zip/Keep.java deleted file mode 100644 index bc647b6..0000000 --- a/zip/Keep.java +++ /dev/null @@ -1,191 +0,0 @@ -package org.json.zip; - -import java.util.HashMap; - -import org.json.Kim; - -/* - Copyright (c) 2013 JSON.org - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all - copies or substantial portions of the Software. - - The Software shall be used for Good, not Evil. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. - */ - -/** - * A keep is a data structure that associates strings (or substrings) with - * numbers. This allows the sending of small integers instead of strings. - * - * @author JSON.org - * @version 2013-05-03 - */ -class Keep implements None, PostMortem { - private int capacity; - protected int length; - private Object[] list; - private HashMap map; - private int power; - private long[] ticks; - - public Keep(int bits) { - this.capacity = 1 << bits; - this.length = 0; - this.power = 0; - this.ticks = new long[this.capacity]; - this.list = new Object[this.capacity]; - this.map = new HashMap(this.capacity); - } - - /** - * When an item ages, its use count is reduced by at least half. - * - * @param ticks - * The current use count of an item. - * @return The new use count for that item. - */ - public static long age(long ticks) { - return ticks >= 32 ? 16 : ticks / 2; - } - - /** - * Return the number of bits required to contain an integer based on the - * current length of the keep. As the keep fills up, the number of bits - * required to identify one of its items goes up. - */ - public int bitsize() { - while (1 << this.power < this.length) { - this.power += 1; - } - return this.power; - } - - /** - * Increase the usage count on an integer value. - */ - public void tick(int integer) { - this.ticks[integer] += 1; - } - - /** - * Compact the keep. A keep may contain at most this.capacity elements. - * The keep contents can be reduced by deleting all elements with low use - * counts, and by reducing the use counts of the survivors. - */ - private void compact() { - int from = 0; - int to = 0; - while (from < this.capacity) { - Object key = this.list[from]; - long usage = age(this.ticks[from]); - if (usage > 0) { - this.ticks[to] = usage; - this.list[to] = key; - this.map.put(key, to); - to += 1; - } else { - this.map.remove(key); - } - from += 1; - } - if (to < this.capacity) { - this.length = to; - } else { - this.map.clear(); - this.length = 0; - } - this.power = 0; - } - - /** - * Find the integer value associated with this key, or nothing if this key - * is not in the keep. - * - * @param key - * An object. - * @return An integer - */ - public int find(Object key) { - Object o = this.map.get(key); - return o instanceof Integer ? ((Integer) o).intValue() : none; - } - - public boolean postMortem(PostMortem pm) { - Keep that = (Keep) pm; - if (this.length != that.length) { - JSONzip.log(this.length + " <> " + that.length); - return false; - } - for (int i = 0; i < this.length; i += 1) { - boolean b; - if (this.list[i] instanceof Kim) { - b = this.list[i].equals(that.list[i]); - } else { - Object o = this.list[i]; - Object q = that.list[i]; - if (o instanceof Number) { - o = o.toString(); - } - if (q instanceof Number) { - q = q.toString(); - } - b = o.equals(q); - } - if (!b) { - JSONzip.log("\n[" + i + "]\n " + this.list[i] + "\n " - + that.list[i] + "\n " + this.ticks[i] + "\n " - + that.ticks[i]); - return false; - } - } - return true; - } - - /** - * Register a value in the keep. Compact the keep if it is full. The next - * time this value is encountered, its integer can be sent instead. - * @param value A value. - */ - public void register(Object value) { - if (JSONzip.probe) { - int integer = find(value); - if (integer >= 0) { - JSONzip.log("\nDuplicate key " + value); - } - } - if (this.length >= this.capacity) { - compact(); - } - this.list[this.length] = value; - this.map.put(value, this.length); - this.ticks[this.length] = 1; - if (JSONzip.probe) { - JSONzip.log("<" + this.length + " " + value + "> "); - } - this.length += 1; - } - - /** - * Return the value associated with the integer. - * @param integer The number of an item in the keep. - * @return The value. - */ - public Object value(int integer) { - return this.list[integer]; - } -} diff --git a/zip/None.java b/zip/None.java deleted file mode 100644 index 818e68d..0000000 --- a/zip/None.java +++ /dev/null @@ -1,15 +0,0 @@ -package org.json.zip; - -/** - * None is an interface that makes the constant none (short for - * negative one or long for -1) available to any class that implements it. - * The none value is used to stand for an integer that is not an integer, - * such as the negative result of a search. - */ -public interface None { - /** - * Negative One. - */ - public static final int none = -1; - -} diff --git a/zip/PostMortem.java b/zip/PostMortem.java deleted file mode 100644 index 0f220ee..0000000 --- a/zip/PostMortem.java +++ /dev/null @@ -1,47 +0,0 @@ -package org.json.zip; - -/* - Copyright (c) 2013 JSON.org - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all - copies or substantial portions of the Software. - - The Software shall be used for Good, not Evil. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. - */ - -/** - * The PostMortem interface allows for testing the internal state of JSONzip - * processors. Testing that JSONzip can compress an object and reproduce a - * corresponding object is not sufficient. Complete testing requires that the - * same internal data structures were constructed on both ends. If those - * structures are not exactly equivalent, then it is likely that the - * implementations are not correct, even if conventional tests are passed. - * - * PostMortem allows for testing of deep structures without breaking - * encapsulation. - */ -public interface PostMortem { - /** - * Determine if two objects are equivalent. - * - * @param pm - * Another object of the same type. - * @return true if they match. - */ - public boolean postMortem(PostMortem pm); -} diff --git a/zip/README b/zip/README deleted file mode 100644 index 93e6470..0000000 --- a/zip/README +++ /dev/null @@ -1,2 +0,0 @@ -FOR EVALUATION PURPOSES ONLY. THIS PACKAGE HAS NOT BEEN TESTED ADEQUATELY FOR -PRODUCTION USE. diff --git a/zip/Unzipper.java b/zip/Unzipper.java deleted file mode 100644 index a7c308e..0000000 --- a/zip/Unzipper.java +++ /dev/null @@ -1,310 +0,0 @@ -package org.json.zip; - -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; -import org.json.Kim; - -/* - Copyright (c) 2012 JSON.org - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all - copies or substantial portions of the Software. - - The Software shall be used for Good, not Evil. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. - */ - -/** - * JSONzip is a binary compression scheme for JSON text. - * - * @author JSON.org - * @version 2014-05-03 - */ - -public class Unzipper extends JSONzip { - - /** - * A decoder reads bits from a BitReader. - */ - BitReader bitreader; - - /** - * Create a new unzipper. It may be used for an entire session or - * subsession. - * - * @param bitreader - * The bitreader that this decoder will read from. - */ - public Unzipper(BitReader bitreader) { - super(); - this.bitreader = bitreader; - } - - /** - * Read one bit. - * - * @return true if 1, false if 0. - * @throws JSONException - */ - private boolean bit() throws JSONException { - boolean value; - try { - value = this.bitreader.bit(); - if (probe) { - log(value ? 1 : 0); - } - return value; - } catch (Throwable e) { - throw new JSONException(e); - } - - } - - /** - * Read enough bits to obtain an integer from the keep, and increase that - * integer's weight. - * - * @param keep The keep providing the context. - * @param bitreader The bitreader that is the source of bits. - * @return The value associated with the number. - * @throws JSONException - */ - private Object getAndTick(Keep keep, BitReader bitreader) - throws JSONException { - try { - int width = keep.bitsize(); - int integer = bitreader.read(width); - Object value = keep.value(integer); - if (JSONzip.probe) { - JSONzip.log("\"" + value + "\""); - JSONzip.log(integer, width); - } - if (integer >= keep.length) { - throw new JSONException("Deep error."); - } - keep.tick(integer); - return value; - } catch (Throwable e) { - throw new JSONException(e); - } - } - - /** - * The pad method skips the bits that padded a stream to fit some - * allocation. pad(8) will skip over the remainder of a byte. - * - * @param width The width of the pad field in bits. - * @return true if all of the padding bits were zero. - * @throws JSONException - */ - public boolean pad(int width) throws JSONException { - try { - return this.bitreader.pad(width); - } catch (Throwable e) { - throw new JSONException(e); - } - } - - /** - * Read an integer, specifying its width in bits. - * - * @param width - * 0 to 32. - * @return An unsigned integer. - * @throws JSONException - */ - private int read(int width) throws JSONException { - try { - int value = this.bitreader.read(width); - if (probe) { - log(value, width); - } - return value; - } catch (Throwable e) { - throw new JSONException(e); - } - } - - /** - * Read Huffman encoded characters into a keep. - * @param huff A Huffman decoder. - * @param ext A Huffman decoder for the extended bytes. - * @param keep The keep that will receive the kim. - * @return The string that was read. - * @throws JSONException - */ - private String read(Huff huff, Huff ext, Keep keep) throws JSONException { - Kim kim; - int at = 0; - int allocation = 256; - byte[] bytes = new byte[allocation]; - if (bit()) { - return getAndTick(keep, this.bitreader).toString(); - } - while (true) { - if (at >= allocation) { - allocation *= 2; - bytes = java.util.Arrays.copyOf(bytes, allocation); - } - int c = huff.read(this.bitreader); - if (c == end) { - break; - } - while ((c & 128) == 128) { - bytes[at] = (byte) c; - at += 1; - c = ext.read(this.bitreader); - } - bytes[at] = (byte) c; - at += 1; - } - if (at == 0) { - return ""; - } - kim = new Kim(bytes, at); - keep.register(kim); - return kim.toString(); - } - - /** - * Read a JSONArray. - * - * @param stringy - * true if the first element is a string. - * @throws JSONException - */ - private JSONArray readArray(boolean stringy) throws JSONException { - JSONArray jsonarray = new JSONArray(); - jsonarray.put(stringy - ? read(this.stringhuff, this.stringhuffext, this.stringkeep) - : readValue()); - while (true) { - if (probe) { - log(); - } - if (!bit()) { - if (!bit()) { - return jsonarray; - } - jsonarray.put(stringy - ? readValue() - : read(this.stringhuff, this.stringhuffext, - this.stringkeep)); - } else { - jsonarray.put(stringy - ? read(this.stringhuff, this.stringhuffext, - this.stringkeep) - : readValue()); - } - } - } - - /** - * Read a JSON value. The type of value is determined by the next 3 bits. - * - * @return The read value. - * @throws JSONException - */ - private Object readJSON() throws JSONException { - switch (read(3)) { - case zipObject: - return readObject(); - case zipArrayString: - return readArray(true); - case zipArrayValue: - return readArray(false); - case zipEmptyObject: - return new JSONObject(); - case zipEmptyArray: - return new JSONArray(); - case zipTrue: - return Boolean.TRUE; - case zipFalse: - return Boolean.FALSE; - default: - return JSONObject.NULL; - } - } - - private JSONObject readObject() throws JSONException { - JSONObject jsonobject = new JSONObject(); - while (true) { - if (probe) { - log(); - } - String name = read(this.namehuff, this.namehuffext, this.namekeep); - if (jsonobject.opt(name) != null) { - throw new JSONException("Duplicate key."); - } - jsonobject.put(name, !bit() - ? read(this.stringhuff, this.stringhuffext, this.stringkeep) - : readValue()); - if (!bit()) { - return jsonobject; - } - } - } - - private Object readValue() throws JSONException { - switch (read(2)) { - case 0: - int nr_bits = !bit() ? 4 : !bit() ? 7 : 14; - int integer = read(nr_bits); - switch (nr_bits) { - case 7: - integer += int4; - break; - case 14: - integer += int7; - break; - } - return integer; - case 1: - byte[] bytes = new byte[256]; - int length = 0; - while (true) { - int c = read(4); - if (c == endOfNumber) { - break; - } - bytes[length] = bcd[c]; - length += 1; - } - Object value; - try { - value = JSONObject.stringToValue(new String(bytes, 0, length, - "US-ASCII")); - } catch (java.io.UnsupportedEncodingException e) { - throw new JSONException(e); - } - this.valuekeep.register(value); - return value; - case 2: - return getAndTick(this.valuekeep, this.bitreader); - case 3: - return readJSON(); - default: - throw new JSONException("Impossible."); - } - } - - public Object decode() throws JSONException { - generate(); - return readJSON(); - } -} diff --git a/zip/Zipper.java b/zip/Zipper.java deleted file mode 100644 index 48b4f1a..0000000 --- a/zip/Zipper.java +++ /dev/null @@ -1,481 +0,0 @@ -package org.json.zip; - -import java.util.Collection; -import java.util.Iterator; -import java.util.Map; - -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; -import org.json.Kim; - -/* - Copyright (c) 2013 JSON.org - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all - copies or substantial portions of the Software. - - The Software shall be used for Good, not Evil. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. - */ - -/** - * JSONzip is a binary compression scheme for JSON text. - * - * @author JSON.org - * @version 2014-05-03 - */ - -/** - * An encoder implements the compression behavior of JSONzip. It provides a - * zip method that takes a JSONObject or JSONArray and delivers a stream of - * bits to a BitWriter. - * - * FOR EVALUATION PURPOSES ONLY. THIS PACKAGE HAS NOT BEEN TESTED ADEQUATELY - * FOR PRODUCTION USE. - */ -public class Zipper extends JSONzip { - - /** - * An encoder outputs to a BitWriter. - */ - final BitWriter bitwriter; - - /** - * Create a new encoder. It may be used for an entire session or - * subsession. - * - * @param bitwriter - * The BitWriter this encoder will output to. - * Don't forget to flush. - */ - public Zipper(BitWriter bitwriter) { - super(); - this.bitwriter = bitwriter; - } - - /** - * Return a 4 bit code for a character in a JSON number. The digits '0' to - * '9' get the codes 0 to 9. '.' is 10, '-' is 11, '+' is 12, and 'E' or - * 'e' is 13. - * - * @param digit - * An ASCII character from a JSON number. - * @return The number code. - */ - private static int bcd(char digit) { - if (digit >= '0' && digit <= '9') { - return digit - '0'; - } - switch (digit) { - case '.': - return 10; - case '-': - return 11; - case '+': - return 12; - default: - return 13; - } - } - - /** - * Finish the final byte and flush the bitwriter. This does the same thing - * as pad(8). - * - * @throws JSONException - */ - public void flush() throws JSONException { - pad(8); - } - - /** - * Output a one bit. - * - * @throws JSONException - */ - private void one() throws JSONException { - write(1, 1); - } - - /** - * Pad the output to fill an allotment of bits. - * - * @param width - * The size of the bit allotment. A value of 8 will complete and - * flush the current byte. If you don't pad, then some of the - * last bits might not be sent to the Output Stream. - * @throws JSONException - */ - public void pad(int width) throws JSONException { - try { - this.bitwriter.pad(width); - } catch (Throwable e) { - throw new JSONException(e); - } - } - - /** - * Write a number, using the number of bits necessary to hold the number. - * - * @param integer - * The value to be encoded. - * @param width - * The number of bits to encode the value, between 0 and 32. - * @throws JSONException - */ - private void write(int integer, int width) throws JSONException { - try { - this.bitwriter.write(integer, width); - if (probe) { - log(integer, width); - } - } catch (Throwable e) { - throw new JSONException(e); - } - } - - /** - * Write an integer with Huffman encoding. The bit pattern that is written - * will be determined by the Huffman encoder. - * - * @param integer - * The value to be written. - * @param huff - * The Huffman encoder. - * @throws JSONException - */ - private void write(int integer, Huff huff) throws JSONException { - huff.write(integer, this.bitwriter); - } - - /** - * Write each of the bytes in a kim with Huffman encoding. - * - * @param kim - * A kim containing the bytes to be written. - * @param huff - * The Huffman encoder. - * @param ext - * The Huffman encoder for the extended bytes. - * @throws JSONException - */ - private void write(Kim kim, Huff huff, Huff ext) throws JSONException { - for (int at = 0; at < kim.length; at += 1) { - int c = kim.get(at); - write(c, huff); - while ((c & 128) == 128) { - at += 1; - c = kim.get(at); - write(c, ext); - } - } - } - - /** - * Write an integer, using the number of bits necessary to hold the number - * as determined by its keep, and increment its usage count in the keep. - * - * @param integer - * The value to be encoded. - * @param keep - * The Keep that the integer is one of. - * @throws JSONException - */ - private void write(int integer, Keep keep) throws JSONException { - int width = keep.bitsize(); - keep.tick(integer); - if (probe) { - log("\"" + keep.value(integer) + "\""); - } - write(integer, width); - } - - /** - * Write a JSON Array. - * - * @param jsonarray The JSONArray to write. - * @throws JSONException If the write fails. - */ - private void write(JSONArray jsonarray) throws JSONException { - -// JSONzip has three encodings for arrays: -// The array is empty (zipEmptyArray). -// First value in the array is a string (zipArrayString). -// First value in the array is not a string (zipArrayValue). - - boolean stringy = false; - int length = jsonarray.length(); - if (length == 0) { - write(zipEmptyArray, 3); - } else { - Object value = jsonarray.get(0); - if (value == null) { - value = JSONObject.NULL; - } - if (value instanceof String) { - stringy = true; - write(zipArrayString, 3); - writeString((String) value); - } else { - write(zipArrayValue, 3); - writeValue(value); - } - for (int i = 1; i < length; i += 1) { - if (probe) { - log(); - } - value = jsonarray.get(i); - if (value == null) { - value = JSONObject.NULL; - } - if (value instanceof String != stringy) { - zero(); - } - one(); - if (value instanceof String) { - writeString((String) value); - } else { - writeValue(value); - } - } - zero(); - zero(); - - } - } - - /** - * Write a JSON value. - * - * @param value - * One of these types: JSONObject, JSONArray (or Map or - * Collection or array), Number (or Integer or Long or Double), - * or String, or Boolean, or JSONObject.NULL, or null. - * @throws JSONException - */ - private void writeJSON(Object value) throws JSONException { - if (JSONObject.NULL.equals(value)) { - write(zipNull, 3); - } else if (Boolean.FALSE.equals(value)) { - write(zipFalse, 3); - } else if (Boolean.TRUE.equals(value)) { - write(zipTrue, 3); - } else { - if (value instanceof Map) { - value = new JSONObject((Map) value); - } else if (value instanceof Collection) { - value = new JSONArray((Collection) value); - } else if (value.getClass().isArray()) { - value = new JSONArray(value); - } - if (value instanceof JSONObject) { - write((JSONObject) value); - } else if (value instanceof JSONArray) { - write((JSONArray) value); - } else { - throw new JSONException("Unrecognized object"); - } - } - } - - /** - * Write the name of an object property. Names have their own Keep and - * Huffman encoder because they are expected to be a more restricted set. - * - * @param name The name string. - * @throws JSONException - */ - private void writeName(String name) throws JSONException { - -// If this name has already been registered, then emit its integer and -// increment its usage count. - - Kim kim = new Kim(name); - int integer = this.namekeep.find(kim); - if (integer != none) { - one(); - write(integer, this.namekeep); - } else { - -// Otherwise, emit the string with Huffman encoding, and register it. - - zero(); - write(kim, this.namehuff, this.namehuffext); - write(end, namehuff); - this.namekeep.register(kim); - } - } - - /** - * Write a JSON object. - * - * @param jsonobject The JSONObject to be written. - * @throws JSONException - */ - private void write(JSONObject jsonobject) throws JSONException { - -// JSONzip has two encodings for objects: Empty Objects (zipEmptyObject) and -// non-empty objects (zipObject). - - boolean first = true; - Iterator keys = jsonobject.keys(); - while (keys.hasNext()) { - if (probe) { - log(); - } - Object key = keys.next(); - if (key instanceof String) { - if (first) { - first = false; - write(zipObject, 3); - } else { - one(); - } - writeName((String) key); - Object value = jsonobject.get((String) key); - if (value instanceof String) { - zero(); - writeString((String) value); - } else { - one(); - writeValue(value); - } - } - } - if (first) { - write(zipEmptyObject, 3); - } else { - zero(); - } - } - - /** - * Write a string. - * - * @param string The string to write. - * @throws JSONException - */ - private void writeString(String string) throws JSONException { - -// Special case for empty strings. - - if (string.length() == 0) { - zero(); - write(end, this.stringhuff); - } else { - Kim kim = new Kim(string); - -// Look for the string in the strings keep. If it is found, emit its -// integer and count that as a use. - - int integer = this.stringkeep.find(kim); - if (integer != none) { - one(); - write(integer, this.stringkeep); - } else { - -// But if it is not found, emit the string's characters. Register the string -// so that a later lookup can succeed. - - zero(); - write(kim, this.stringhuff, this.stringhuffext); - write(end, this.stringhuff); - this.stringkeep.register(kim); - } - } - } - - /** - * Write a value. - * - * @param value - * One of these types: Boolean, Number, etc. - * @throws JSONException - */ - private void writeValue(Object value) throws JSONException { - if (value instanceof Number) { - String string = JSONObject.numberToString((Number) value); - int integer = this.valuekeep.find(string); - if (integer != none) { - write(2, 2); - write(integer, this.valuekeep); - return; - } - if (value instanceof Integer || value instanceof Long) { - long longer = ((Number) value).longValue(); - if (longer >= 0 && longer < int14) { - write(0, 2); - if (longer < int4) { - zero(); - write((int) longer, 4); - return; - } - one(); - if (longer < int7) { - zero(); - write((int)(longer - int4), 7); - return; - } - one(); - write((int)(longer - int7), 14); - return; - } - } - write(1, 2); - for (int i = 0; i < string.length(); i += 1) { - write(bcd(string.charAt(i)), 4); - } - write(endOfNumber, 4); - this.valuekeep.register(string); - } else { - write(3, 2); - writeJSON(value); - } - } - - /** - * Output a zero bit. - * - * @throws JSONException - */ - private void zero() throws JSONException { - write(0, 1); - } - - /** - * Encode a JSONObject. - * - * @param jsonobject The JSONObject. - * @throws JSONException - */ - public void encode(JSONObject jsonobject) throws JSONException { - generate(); - writeJSON(jsonobject); - } - - /** - * Encode a JSONArray. - * - * @param jsonarray The JSONArray. - * @throws JSONException - */ - public void encode(JSONArray jsonarray) throws JSONException { - generate(); - writeJSON(jsonarray); - } -}