All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.sourceforge.plantuml.code.deflate.CanonicalCode Maven / Gradle / Ivy

There is a newer version: 1.2024.8
Show newest version
// THIS FILE HAS BEEN GENERATED BY A PREPROCESSOR.
/* +=======================================================================
 * |
 * |      PlantUML : a free UML diagram generator
 * |
 * +=======================================================================
 *
 * (C) Copyright 2009-2024, Arnaud Roques
 *
 * Project Info:  https://plantuml.com
 *
 * If you like this project or if you find it useful, you can support us at:
 *
 * https://plantuml.com/patreon (only 1$ per month!)
 * https://plantuml.com/liberapay (only 1€ per month!)
 * https://plantuml.com/paypal
 *
 *
 * PlantUML is free software; you can redistribute it and/or modify it
 * under the terms of the Eclipse Public License.
 *
 * THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC
 * LICENSE ("AGREEMENT"). [Eclipse Public License - v 1.0]
 *
 * ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM CONSTITUTES
 * RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT.
 *
 * You may obtain a copy of the License at
 *
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * PlantUML can occasionally display sponsored or advertising messages. Those
 * messages are usually generated on welcome or error images and never on
 * functional diagrams.
 * See https://plantuml.com/professional if you want to remove them
 *
 * Images (whatever their format : PNG, SVG, EPS...) generated by running PlantUML
 * are owned by the author of their corresponding sources code (that is, their
 * textual description in PlantUML language). Those images are not covered by
 * this EPL license.
 *
 * The generated images can then be used without any reference to the EPL license.
 * It is not even necessary to stipulate that they have been generated with PlantUML,
 * although this will be appreciated by the PlantUML team.
 *
 * There is an exception : if the textual description in PlantUML language is also covered
 * by any license, then the generated images are logically covered
 * by the very same license.
 *
 * This is the IGY distribution (Install GraphViz by Yourself).
 * You have to install GraphViz and to setup the GRAPHVIZ_DOT environment variable
 * (see https://plantuml.com/graphviz-dot )
 *
 * Icons provided by OpenIconic :  https://useiconic.com/open
 * Archimate sprites provided by Archi :  http://www.archimatetool.com
 * Stdlib AWS provided by https://github.com/milo-minderbinder/AWS-PlantUML
 * Stdlib Icons provided https://github.com/tupadr3/plantuml-icon-font-sprites
 * ASCIIMathML (c) Peter Jipsen http://www.chapman.edu/~jipsen
 * ASCIIMathML (c) David Lippman http://www.pierce.ctc.edu/dlippman
 * CafeUndZopfli ported by Eugene Klyuchnikov https://github.com/eustas/CafeUndZopfli
 * Brotli (c) by the Brotli Authors https://github.com/google/brotli
 * Themes (c) by Brett Schwarz https://github.com/bschwarz/puml-themes
 * Twemoji (c) by Twitter at https://twemoji.twitter.com/
 *
 */
package net.sourceforge.plantuml.code.deflate;

/* 
 * Simple DEFLATE decompressor
 * Copyright (c) Project Nayuki
 * 
 * https://www.nayuki.io/page/simple-deflate-decompressor
 * https://github.com/nayuki/Simple-DEFLATE-decompressor
 */

import java.io.IOException;
import java.util.Arrays;
import java.util.Objects;

/**
 * A canonical Huffman code, where the code values for each symbol is derived
 * from a given sequence of code lengths. This data structure is immutable. This
 * could be transformed into an explicit Huffman code tree.
 * 

* Example: *

* *
 *   Code lengths (canonical code):
 *    Symbol A: 1
 *    Symbol B: 0 (no code)
 *    Symbol C: 3
 *    Symbol D: 2
 *    Symbol E: 3
 *  
 *  Generated Huffman codes:
 *    Symbol A: 0
 *    Symbol B: (Absent)
 *    Symbol C: 110
 *    Symbol D: 10
 *    Symbol E: 111
 *  
 *  Huffman code tree:
 *      .
 *     / \
 *    A   .
 *       / \
 *      D   .
 *         / \
 *        C   E
 * 
*/ final class CanonicalCode { /* * These arrays store the Huffman codes and values necessary for decoding. * symbolCodeBits contains Huffman codes, each padded with a 1 bit at the * beginning to disambiguate codes of different lengths (e.g. otherwise we can't * distinguish 0b01 from 0b0001). Each symbolCodeBits[i] decodes to its * corresponding symbolValues[i]. Values in symbolCodeBits are strictly * increasing. * * For the example of codeLengths=[1,0,3,2,3], we would have: i | * symbolCodeBits[i] | symbolValues[i] --+-------------------+---------------- 0 * | 0b1_0 | 0 1 | 0b1_10 | 3 2 | 0b1_110 | 2 3 | 0b1_111 | 4 */ private int[] symbolCodeBits; private int[] symbolValues; /** * Constructs a canonical Huffman code from the specified array of symbol code * lengths. Each code length must be non-negative. Code length 0 means no code * for the symbol. The collection of code lengths must represent a proper full * Huffman code tree. *

* Examples of code lengths that result in correct full Huffman code trees: *

*
    *
  • [1, 1] (result: A=0, B=1)
  • *
  • [2, 2, 1, 0, 0, 0] (result: A=10, B=11, C=0)
  • *
  • [3, 3, 3, 3, 3, 3, 3, 3] (result: A=000, B=001, C=010, ..., H=111)
  • *
*

* Examples of code lengths that result in under-full Huffman code trees: *

*
    *
  • [0, 2, 0] (result: B=00, unused=01, unused=1)
  • *
  • [0, 1, 0, 2] (result: B=0, D=10, unused=11)
  • *
*

* Examples of code lengths that result in over-full Huffman code trees: *

*
    *
  • [1, 1, 1] (result: A=0, B=1, C=overflow)
  • *
  • [1, 1, 2, 2, 3, 3, 3, 3] (result: A=0, B=1, C=overflow, ...)
  • *
* * @param codeLengths array of symbol code lengths (not {@code null}) * @throws NullPointerException if the array is {@code null} * @throws IllegalArgumentException if any element is negative, any value * exceeds MAX_CODE_LENGTH, or the collection * of code lengths would yield an under-full or * over-full Huffman code tree */ public CanonicalCode(int[] codeLengths) { // Check argument values Objects.requireNonNull(codeLengths); for (int x : codeLengths) { if (x < 0) throw new IllegalArgumentException("Negative code length"); if (x > MAX_CODE_LENGTH) throw new IllegalArgumentException("Maximum code length exceeded"); } // Allocate code values to symbols. Symbols are processed in the order // of shortest code length first, breaking ties by lowest symbol value. symbolCodeBits = new int[codeLengths.length]; symbolValues = new int[codeLengths.length]; int numSymbolsAllocated = 0; int nextCode = 0; for (int codeLength = 1; codeLength <= MAX_CODE_LENGTH; codeLength++) { nextCode <<= 1; int startBit = 1 << codeLength; for (int symbol = 0; symbol < codeLengths.length; symbol++) { if (codeLengths[symbol] != codeLength) continue; if (nextCode >= startBit) throw new IllegalArgumentException("This canonical code produces an over-full Huffman code tree"); symbolCodeBits[numSymbolsAllocated] = startBit | nextCode; symbolValues[numSymbolsAllocated] = symbol; numSymbolsAllocated++; nextCode++; } } if (nextCode != 1 << MAX_CODE_LENGTH) throw new IllegalArgumentException("This canonical code produces an under-full Huffman code tree"); // Trim unused trailing elements symbolCodeBits = Arrays.copyOf(symbolCodeBits, numSymbolsAllocated); symbolValues = Arrays.copyOf(symbolValues, numSymbolsAllocated); } /** * Decodes the next symbol from the specified bit input stream based on this * canonical code. The returned symbol value is in the range [0, * codeLengths.length). * * @param in the bit input stream to read from * @return the next decoded symbol * @throws IOException if an I/O exception occurred */ public int decodeNextSymbol(BitInputStream in) throws IOException { Objects.requireNonNull(in); int codeBits = 1; // The start bit while (true) { // Accumulate one bit at a time on the right side until a match is // found in the symbolCodeBits array. Because the Huffman code tree is // full, this loop must terminate after at most MAX_CODE_LENGTH iterations. codeBits = codeBits << 1 | in.readNoEof(); int index = Arrays.binarySearch(symbolCodeBits, codeBits); if (index >= 0) return symbolValues[index]; } } /** * Returns a string representation of this canonical code, useful for debugging * only, and the format is subject to change. * * @return a string representation of this canonical code */ public String toString() { StringBuilder sb = new StringBuilder(); for (int i = 0; i < symbolCodeBits.length; i++) { sb.append(String.format("Code %s: Symbol %d%n", Integer.toBinaryString(symbolCodeBits[i]).substring(1), symbolValues[i])); } return sb.toString(); } // The maximum Huffman code length allowed in the DEFLATE standard. private static final int MAX_CODE_LENGTH = 15; }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy