net.sourceforge.plantuml.zopfli.Squeeze Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of plantuml-mit Show documentation
Show all versions of plantuml-mit Show documentation
PlantUML is a component that allows to quickly write diagrams from text.
// 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 MIT License.
*
* See http://opensource.org/licenses/MIT
*
* 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 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.
*
* 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 MIT license.
*
* The generated images can then be used without any reference to the MIT 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.zopfli;
class Squeeze {
static LzStore optimal(Cookie cookie, int numIterations, LongestMatchCache lmc, byte[] input, int from, int to) {
LzStore currentStore = cookie.store1;
currentStore.reset();
LzStore store = cookie.store2;
Deflate.greedy(cookie, lmc, input, from, to, currentStore);
SymbolStats stats = cookie.stats;
SymbolStats bestStats = cookie.bestStats;
SymbolStats lastStats = cookie.lastStats;
stats.getFreqs(currentStore);
char[] lengthArray = cookie.lengthArray;
long[] costs = cookie.costs;
int cost;
int bestCost = Integer.MAX_VALUE;
int lastCost = 0;
int lastRandomStep = -1;
for (int i = 0; i < numIterations; i++) {
currentStore.reset();
bestLengths(cookie, lmc, from, input, from, to, stats.minCost(), stats, lengthArray, costs);
optimalRun(cookie, lmc, input, from, to, lengthArray, currentStore);
cost = Deflate.calculateBlockSize(cookie, currentStore.litLens, currentStore.dists, 0, currentStore.size);
if (cost < bestCost) {
store.copy(currentStore);
bestStats.copy(stats);
bestCost = cost;
}
lastStats.copy(stats);
stats.getFreqs(currentStore);
if (lastRandomStep != -1) {
stats.alloy(lastStats);
stats.calculate();
}
if (i > 5 && cost == lastCost) {
stats.copy(bestStats);
cookie.rnd = stats.randomizeFreqs(cookie.rnd);
stats.calculate();
lastRandomStep = i;
}
lastCost = cost;
}
return store;
}
static void optimalRun(Cookie cookie, LongestMatchCache lmc, byte[] input, int from, int to, char[] lengthArray,
LzStore store) {
// assert from != to
char[] path = cookie.path;
int pathSize = 0;
int size = to - from;
do {
char las = lengthArray[size];
path[pathSize++] = las;
size -= las;
} while (size != 0);
int windowStart = Math.max(from - 0x8000, 0);
Hash h = cookie.h;
h.init(input, windowStart, from, to);
int pos = from;
do {
h.updateHash(input, pos, to);
int length = path[--pathSize];
if (length >= 3) {
Deflate.findLongestMatch(cookie, lmc, from, h, input, pos, to, length, null);
store.append((char) length, (char) cookie.distVal);
} else {
length = 1;
store.append((char) (input[pos] & 0xFF), (char) 0);
}
for (int j = 1; j < length; ++j) {
h.updateHash(input, pos + j, to);
}
pos += length;
} while (pathSize != 0);
}
private static long fixedCost(int litLen, int dist) {
if (dist == 0) {
if (litLen <= 143) {
return 8;
}
return 9;
} else {
long cost = 12
+ (dist < 4097 ? Util.CACHED_DIST_EXTRA_BITS[dist] : dist < 16385 ? dist < 8193 ? 11 : 12 : 13)
+ Util.LENGTH_EXTRA_BITS[litLen];
if (Util.LENGTH_SYMBOL[litLen] > 279) {
return cost + 1;
}
return cost;
}
}
private static void bestLengths(Cookie cookie, LongestMatchCache lmc, int blockStart, byte[] input, int from,
int to, long minCost, SymbolStats stats, char[] lengthArray, long[] costs) {
// # WINDOW_SIZE = 0x8000
// # WINDOW_MASK = 0x7FFF
// # MAX_MATCH = 258
int windowStart = Math.max(from - 0x8000, 0);
Hash h = cookie.h;
h.init(input, windowStart, from, to);
Cookie.fillCostMax(costs, to - from + 1);
costs[0] = 0L;
lengthArray[0] = 0;
int[] same = h.same;
char[] subLen = cookie.c259a;
System.arraycopy(Cookie.charZeroes, 0, subLen, 0, 259);
long[] slLiterals = stats.lLiterals;
long[] slLengths = stats.lLengths;
long[] sdSymbols = stats.dSymbols;
long stepCost = slLengths[258] + sdSymbols[0];
int[] cachedDistSymbol = Util.CACHED_DIST_SYMBOL;
int i = from;
int j = 0;
while (i < to) {
h.updateHash(input, i, to);
if (same[i & 0x7FFF] > 516 && i > from + 259 && i + 517 < to && same[(i - 258) & 0x7FFF] > 258) {
for (int k = 0; k < 258; ++k) {
costs[j + 258] = costs[j] + stepCost;
lengthArray[j + 258] = 258;
i++;
j++;
h.updateHash(input, i, to);
}
}
Deflate.findLongestMatch(cookie, lmc, blockStart, h, input, i, to, 258, subLen);
long costsJ = costs[j];
if (i + 1 <= to) {
long newCost = costsJ + slLiterals[input[i] & 0xFF];
if (newCost < costs[j + 1]) {
costs[j + 1] = newCost;
lengthArray[j + 1] = 1;
}
}
int lenValue = cookie.lenVal;
long baseCost = minCost + costsJ;
if (lenValue > to - i) {
lenValue = to - i;
}
int jpk = j + 3;
for (char k = 3; k <= lenValue; k++, jpk++) {
if (costs[jpk] > baseCost) {
long newCost = costsJ + (slLengths[k] + sdSymbols[cachedDistSymbol[subLen[k]]]);
if (costs[jpk] > newCost) {
costs[jpk] = newCost;
lengthArray[jpk] = k;
}
}
}
i++;
j++;
}
}
static void bestFixedLengths(Cookie cookie, LongestMatchCache lmc, byte[] input, int from, int to,
char[] lengthArray, long[] costs) {
int windowStart = Math.max(from - 0x8000, 0);
Hash h = cookie.h;
h.init(input, windowStart, from, to);
Cookie.fillCostMax(costs, to - from + 1);
costs[0] = 0L;
lengthArray[0] = 0;
char[] subLen = cookie.c259a;
for (int i = from; i < to; i++) {
int j = i - from;
h.updateHash(input, i, to);
if (h.same[i & 0x7FFF] > 258 * 2 && i > from + 258 + 1 && i + 258 * 2 + 1 < to
&& h.same[(i - 258) & 0x7FFF] > 258) {
long symbolCost = fixedCost(258, 1);
for (int k = 0; k < 258; k++) {
costs[j + 258] = costs[j] + symbolCost;
lengthArray[j + 258] = 258;
i++;
j++;
h.updateHash(input, i, to);
}
}
Deflate.findLongestMatch(cookie, lmc, from, h, input, i, to, 258, subLen);
if (i + 1 <= to) {
long newCost = costs[j] + fixedCost(input[i] & 0xFF, 0);
if (newCost < costs[j + 1]) {
costs[j + 1] = newCost;
lengthArray[j + 1] = 1;
}
}
int lenValue = cookie.lenVal;
for (char k = 3; k <= lenValue && i + k <= to; k++) {
if (costs[j + k] - costs[j] <= 12.0) {
continue;
}
long newCost = costs[j] + fixedCost(k, subLen[k]);
if (newCost < costs[j + k]) {
costs[j + k] = newCost;
lengthArray[j + k] = k;
}
}
}
}
}