version 1.2017.20

This commit is contained in:
Arnaud Roques 2017-12-11 22:02:10 +01:00
parent c3662b656e
commit c17f4a1254
2260 changed files with 5874 additions and 347191 deletions

View File

@ -58,7 +58,7 @@
</copy>
<copy todir="build/stdlib">
<fileset dir="stdlib">
<include name="**/*.puml" />
<include name="**/*.repx" />
</fileset>
</copy>
</target>

View File

@ -35,7 +35,7 @@
<groupId>net.sourceforge.plantuml</groupId>
<artifactId>plantuml</artifactId>
<version>1.2017.20-SNAPSHOT</version>
<version>1.2017.21-SNAPSHOT</version>
<packaging>jar</packaging>
<name>PlantUML</name>
@ -123,7 +123,7 @@
<resource>
<directory>${project.basedir}</directory>
<includes>
<include>stdlib/**/*.puml</include>
<include>stdlib/**/*.repx</include>
</includes>
</resource>
</resources>

View File

@ -43,7 +43,8 @@ public enum AlignParam {
ARROW_MESSAGE_ALIGN(HorizontalAlignment.LEFT),
SEQUENCE_MESSAGE_ALIGN(HorizontalAlignment.LEFT),
SEQUENCE_MESSAGETEXT_ALIGN(HorizontalAlignment.LEFT),
SEQUENCE_REFERENCE_ALIGN(HorizontalAlignment.CENTER);
SEQUENCE_REFERENCE_ALIGN(HorizontalAlignment.CENTER),
PACKAGE_TITLE_ALIGNMENT(HorizontalAlignment.CENTER);
private final HorizontalAlignment defaultValue;

View File

@ -57,6 +57,10 @@ public class BasicEnsureVisible implements EnsureVisible {
}
}
public boolean hasData() {
return minX != Double.MAX_VALUE;
}
public String getCoords(double scale) {
if (minX == Double.MAX_VALUE) {
return "0,0,0,0";

View File

@ -60,7 +60,7 @@ public class CMapData {
stringBuilder.append(s);
}
public void appendUrl(int seq, Url url, double scale) {
private void appendUrl(int seq, Url url, double scale) {
appendString("<area shape=\"rect\" id=\"id");
appendLong(seq);
appendString("\" href=\"");
@ -76,9 +76,6 @@ public class CMapData {
appendString(BackSlash.NEWLINE);
}
// private CMapData() {
// }
public static CMapData cmapString(Set<Url> allUrlEncountered, double scale) {
final CMapData cmapdata = new CMapData();
@ -87,6 +84,9 @@ public class CMapData {
int seq = 1;
for (Url u : all) {
if (u.hasData() == false) {
continue;
}
cmapdata.appendUrl(seq, u, scale);
seq++;
}

View File

@ -103,4 +103,21 @@ public class CharSequence2Impl implements CharSequence2 {
return preprocessorError;
}
public CharSequence2 removeInnerComment() {
final String string = s.toString();
final String trim = string.replace('\t', ' ').trim();
if (trim.startsWith("/'")) {
final int idx = string.indexOf("'/");
if (idx != -1) {
return new CharSequence2Impl(s.subSequence(idx + 2, s.length()), location, preprocessorError);
}
}
if (trim.endsWith("'/")) {
final int idx = string.lastIndexOf("/'");
if (idx != -1) {
return new CharSequence2Impl(s.subSequence(0, idx), location, preprocessorError);
}
}
return this;
}
}

View File

@ -35,6 +35,8 @@
*/
package net.sourceforge.plantuml;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
@ -46,8 +48,11 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.URL;
import java.util.concurrent.atomic.AtomicInteger;
import javax.swing.ImageIcon;
// Used by the Eclipse Plugin, so do not change package location.
public class FileUtils {
@ -115,19 +120,27 @@ public class FileUtils {
static public String readSvg(File svgFile) throws IOException {
final BufferedReader br = new BufferedReader(new FileReader(svgFile));
return readSvg(br, true);
return readSvg(br, false, true);
}
static public String readSvg(InputStream is) throws IOException {
final BufferedReader br = new BufferedReader(new InputStreamReader(is));
return readSvg(br, false);
return readSvg(br, false, false);
}
private static String readSvg(final BufferedReader br, boolean withClose) throws IOException {
static public String readFile(File svgFile) throws IOException {
final BufferedReader br = new BufferedReader(new FileReader(svgFile));
return readSvg(br, true, true);
}
private static String readSvg(final BufferedReader br, boolean withNewline, boolean withClose) throws IOException {
final StringBuilder sb = new StringBuilder();
String s;
while ((s = br.readLine()) != null) {
sb.append(s);
if (withNewline) {
sb.append("\n");
}
}
if (withClose) {
br.close();
@ -135,4 +148,36 @@ public class FileUtils {
return sb.toString();
}
// public static BufferedImage ImageIO_read(File f) throws IOException {
// return ImageIO.read(f);
// }
public static BufferedImage ImageIO_read(File f) {
// https://www.experts-exchange.com/questions/26171948/Why-are-ImageIO-read-images-losing-their-transparency.html
// https://stackoverflow.com/questions/18743790/can-java-load-images-with-transparency
try {
return readImage(new ImageIcon(f.getAbsolutePath()));
} catch (Exception e) {
return null;
}
}
public static BufferedImage ImageIO_read(URL url) {
try {
return readImage(new ImageIcon(url));
} catch (Exception e) {
return null;
}
}
private static BufferedImage readImage(final ImageIcon imageIcon) {
final Image tmpImage = imageIcon.getImage();
final BufferedImage image = new BufferedImage(imageIcon.getIconWidth(), imageIcon.getIconHeight(),
BufferedImage.TYPE_INT_ARGB);
image.getGraphics().drawImage(tmpImage, 0, 0, null);
tmpImage.flush();
return image;
}
}

View File

@ -82,6 +82,7 @@ public class Option {
private File outputDir = null;
private File outputFile = null;
private String filename;
private final List<String> result = new ArrayList<String>();
@ -168,6 +169,12 @@ public class Option {
continue;
}
charset = StringUtils.eventuallyRemoveStartingAndEndingDoubleQuote(arg[i]);
} else if (s.equalsIgnoreCase("-filename")) {
i++;
if (i == arg.length) {
continue;
}
filename = StringUtils.eventuallyRemoveStartingAndEndingDoubleQuote(arg[i]);
} else if (s.startsWith("-o") && s.length() > 3) {
s = s.substring(2);
outputDir = new File(StringUtils.eventuallyRemoveStartingAndEndingDoubleQuote(s));
@ -296,6 +303,8 @@ public class Option {
OptionFlags.getInstance().setEnableStats(true);
} else if (s.equalsIgnoreCase("-disablestats")) {
OptionFlags.getInstance().setEnableStats(false);
} else if (s.equalsIgnoreCase("-extractstdlib")) {
OptionFlags.getInstance().setExtractStdLib(true);
} else if (s.equalsIgnoreCase("-htmlstats")) {
StatsUtils.setHtmlStats(true);
} else if (s.equalsIgnoreCase("-xmlstats")) {
@ -548,4 +557,12 @@ public class Option {
return imageIndex;
}
public String getFilename() {
return filename;
}
public final void setFilename(String filename) {
this.filename = filename;
}
}

View File

@ -123,6 +123,7 @@ public class OptionFlags {
private boolean loopStats;
private boolean overwrite;
private boolean enableStats = defaultForStats();
private boolean extractStdLib;
private String fileSeparator = "_";
private long timeoutMs = 15 * 60 * 1000L; // 15 minutes
private File logData;
@ -333,4 +334,12 @@ public class OptionFlags {
public final void setTimeoutMs(long timeoutMs) {
this.timeoutMs = timeoutMs;
}
public void setExtractStdLib(boolean extractStdLib) {
this.extractStdLib = extractStdLib;
}
public boolean getExtractStdLib() {
return extractStdLib;
}
}

View File

@ -141,6 +141,8 @@ public class OptionPrint {
System.out.println(" -splash\t\tTo display a splash screen with some progress bar");
System.out.println(" -progress\t\tTo display a textual progress bar in console");
System.out.println(" -pipeimageindex N\tTo generate the Nth image with pipe option");
System.out.println(" -extractstdlib\tTo extract PlantUML Standard Library into stdlib folder");
System.out.println(" -filename \"example.puml\"\tTo override %filename% variable");
System.out.println();
System.out.println("If needed, you can setup the environment variable GRAPHVIZ_DOT.");
exit();

View File

@ -69,8 +69,8 @@ public class Pipe {
ps.flush();
return error;
}
final SourceStringReader sourceStringReader = new SourceStringReader(Defines.createEmpty(), source,
option.getConfig());
final SourceStringReader sourceStringReader = new SourceStringReader(Defines.createEmpty(option
.getFilename()), source, option.getConfig());
if (option.isComputeurl()) {
for (BlockUml s : sourceStringReader.getBlocks()) {
ps.println(s.getEncodedUrl());
@ -88,11 +88,17 @@ public class Pipe {
ps.println(system.getDescription());
}
} else if (option.isPipeMap()) {
final String result = sourceStringReader.getCMapData(0, option.getFileFormatOption());
ps.println(result);
final String result = sourceStringReader.getCMapData(option.getImageIndex(),
option.getFileFormatOption());
if (result == null) {
ps.println();
} else {
ps.println(result);
}
} else {
final OutputStream os = noStdErr ? new ByteArrayOutputStream() : ps;
final DiagramDescription result = sourceStringReader.outputImage(os, option.getImageIndex(), option.getFileFormatOption());
final DiagramDescription result = sourceStringReader.outputImage(os, option.getImageIndex(),
option.getFileFormatOption());
if (result != null && "(error)".equalsIgnoreCase(result.getDescription())) {
error = true;
manageErrors(noStdErr ? ps : System.err, sourceStringReader);

View File

@ -62,6 +62,7 @@ import net.sourceforge.plantuml.descdiagram.DescriptionDiagramFactory;
import net.sourceforge.plantuml.ftp.FtpServer;
import net.sourceforge.plantuml.objectdiagram.ObjectDiagramFactory;
import net.sourceforge.plantuml.png.MetadataTag;
import net.sourceforge.plantuml.preproc.Stdlib;
import net.sourceforge.plantuml.sequencediagram.SequenceDiagramFactory;
import net.sourceforge.plantuml.statediagram.StateDiagramFactory;
import net.sourceforge.plantuml.stats.StatsUtils;
@ -77,6 +78,10 @@ public class Run {
saveCommandLine(argsArray);
final Option option = new Option(argsArray);
ProgressBar.setEnable(option.isTextProgressBar());
if (OptionFlags.getInstance().getExtractStdLib()) {
Stdlib.extractStdLib();
return;
}
if (OptionFlags.getInstance().isDumpStats()) {
StatsUtils.dumpStats();
return;

View File

@ -114,6 +114,10 @@ public class Url implements EnsureVisible {
visible.ensureVisible(x, y);
}
public boolean hasData() {
return visible.hasData();
}
public static final Comparator<Url> SURFACE_COMPARATOR = new Comparator<Url>() {
public int compare(Url url1, Url url2) {
final double surface1 = url1.visible.getSurface();

View File

@ -38,6 +38,7 @@ package net.sourceforge.plantuml.activitydiagram3.ftile.vcompact;
import java.awt.geom.Dimension2D;
import java.util.Set;
import net.sourceforge.plantuml.AlignParam;
import net.sourceforge.plantuml.FontParam;
import net.sourceforge.plantuml.ISkinParam;
import net.sourceforge.plantuml.LineParam;
@ -82,7 +83,7 @@ public class FtileGroup extends AbstractFtile {
super(inner.skinParam());
this.backColor = backColor == null ? HtmlColorUtils.WHITE : backColor;
this.inner = FtileUtils.addHorizontalMargin(inner, 10);
this.borderColor = backColor == null ? HtmlColorUtils.BLACK : borderColor;
this.borderColor = borderColor == null ? HtmlColorUtils.BLACK : borderColor;
final UFont font = skinParam.getFont(null, false, FontParam.PARTITION);
final HtmlColor fontColor = skinParam.getFontHtmlColor(null, FontParam.PARTITION);
@ -195,8 +196,8 @@ public class FtileGroup extends AbstractFtile {
final SymbolContext symbolContext = new SymbolContext(backColor, borderColor).withShadow(
skinParam().shadowing()).withStroke(stroke);
USymbol.FRAME.asBig(name, TextBlockUtils.empty(0, 0), dimTotal.getWidth(), dimTotal.getHeight(), symbolContext)
.drawU(ug);
USymbol.FRAME.asBig(name, inner.skinParam().getHorizontalAlignment(AlignParam.PACKAGE_TITLE_ALIGNMENT, null),
TextBlockUtils.empty(0, 0), dimTotal.getWidth(), dimTotal.getHeight(), symbolContext).drawU(ug);
final Dimension2D dimHeaderNote = headerNote.calculateDimension(stringBounder);
headerNote.drawU(ug.apply(new UTranslate(dimTotal.getWidth() - dimHeaderNote.getWidth() - 10,

View File

@ -37,10 +37,11 @@ package net.sourceforge.plantuml.code;
public class AsciiEncoder implements URLEncoder {
final private char encode6bit[] = new char[64];
final private byte decode6bit[] = new byte[128];
// Temporary because of AsciiEncoderFinalZeros
final static/* private */char encode6bit[] = new char[64];
final static/* private */byte decode6bit[] = new byte[128];
public AsciiEncoder() {
static {
for (byte b = 0; b < 64; b++) {
encode6bit[b] = encode6bit(b);
decode6bit[encode6bit[b]] = b;
@ -51,32 +52,55 @@ public class AsciiEncoder implements URLEncoder {
if (data == null) {
return "";
}
final StringBuilder resu = new StringBuilder((data.length * 4 + 2) / 3);
final StringBuilder result = new StringBuilder((data.length * 4 + 2) / 3);
for (int i = 0; i < data.length; i += 3) {
append3bytes(resu, data[i] & 0xFF, i + 1 < data.length ? data[i + 1] & 0xFF : 0,
append3bytes(result, data[i] & 0xFF, i + 1 < data.length ? data[i + 1] & 0xFF : 0,
i + 2 < data.length ? data[i + 2] & 0xFF : 0);
}
return resu.toString();
return result.toString();
}
public byte[] decode(String s) {
if (s.length() % 4 != 0) {
throw new IllegalArgumentException("Cannot decode " + s);
}
final byte data[] = new byte[(s.length() * 3 + 3) / 4];
// if (s.length() % 4 != 0) {
// throw new IllegalArgumentException("Cannot decode " + s);
// }
final byte data[] = new byte[computeSize(s.length())];
int pos = 0;
for (int i = 0; i < s.length(); i += 4) {
decode3bytes(data, pos, s.charAt(i), s.charAt(i + 1), s.charAt(i + 2), s.charAt(i + 3));
decode3bytes(data, pos, scharAt(s, i), scharAt(s, i + 1), scharAt(s, i + 2), scharAt(s, i + 3));
pos += 3;
}
return data;
}
public int decode6bit(char c) {
private int computeSize(int length) {
// while (length % 4 != 0) {
// length++;
// }
final int r = length % 4;
if (r != 0) {
length += 4 - r;
}
// System.err.println("length=" + length);
// System.err.println("length1=" + (length % 4));
// length += length % 4;
// System.err.println("length2=" + length);
assert length % 4 == 0 : "length=" + length;
return (length * 3 + 3) / 4;
}
private char scharAt(String s, int i) {
if (i >= s.length()) {
return '0';
}
return s.charAt(i);
}
public static int decode6bit(char c) {
return decode6bit[c];
}
public char encode6bit(byte b) {
public static char encode6bit(byte b) {
assert b >= 0 && b < 64;
if (b < 10) {
return (char) ('0' + b);

View File

@ -0,0 +1,66 @@
/* ========================================================================
* PlantUML : a free UML diagram generator
* ========================================================================
*
* (C) Copyright 2009-2017, Arnaud Roques
*
* Project Info: http://plantuml.com
*
* If you like this project or if you find it useful, you can support us at:
*
* http://plantuml.com/patreon (only 1$ per month!)
* http://plantuml.com/paypal
*
* This file is part of PlantUML.
*
* PlantUML is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* PlantUML distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
* License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*
*
* Original Author: Arnaud Roques
*
*
*/
package net.sourceforge.plantuml.code;
public class AsciiEncoderFinalZeros {
public String encode(byte data[]) {
if (data == null) {
return "";
}
final StringBuilder result = new StringBuilder((data.length * 4 + 2) / 3);
for (int i = 0; i < data.length; i += 3) {
append3bytes(result, data[i] & 0xFF, i + 1 < data.length ? data[i + 1] & 0xFF : 0,
i + 2 < data.length ? data[i + 2] & 0xFF : 0);
}
while (result.length() > 0 && result.charAt(result.length() - 1) == '0') {
result.setLength(result.length() - 1);
}
return result.toString();
}
private void append3bytes(StringBuilder sb, int b1, int b2, int b3) {
final int c1 = b1 >> 2;
final int c2 = ((b1 & 0x3) << 4) | (b2 >> 4);
final int c3 = ((b2 & 0xF) << 2) | (b3 >> 6);
final int c4 = b3 & 0x3F;
sb.append(AsciiEncoder.encode6bit[c1 & 0x3F]);
sb.append(AsciiEncoder.encode6bit[c2 & 0x3F]);
sb.append(AsciiEncoder.encode6bit[c3 & 0x3F]);
sb.append(AsciiEncoder.encode6bit[c4 & 0x3F]);
}
}

View File

@ -38,47 +38,24 @@ package net.sourceforge.plantuml.code;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
public class CompressionGZip implements Compression {
import net.sourceforge.plantuml.FileUtils;
class MyGZIPOutputStream extends GZIPOutputStream {
import org.brotli.dec.BrotliInputStream;
public MyGZIPOutputStream(OutputStream baos) throws IOException {
super(baos);
def.setLevel(9);
}
}
public class CompressionBrotli implements Compression {
public byte[] compress(byte[] in) {
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
try {
final GZIPOutputStream gz = new MyGZIPOutputStream(baos);
gz.write(in);
gz.close();
baos.close();
return baos.toByteArray();
} catch (IOException e) {
throw new IllegalStateException(e.toString());
}
throw new UnsupportedOperationException();
}
public byte[] decompress(byte[] in) throws IOException {
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
final ByteArrayInputStream bais = new ByteArrayInputStream(in);
final GZIPInputStream gz = new GZIPInputStream(bais);
int read;
while ((read = gz.read()) != -1) {
baos.write(read);
}
gz.close();
bais.close();
baos.close();
return baos.toByteArray();
final BrotliInputStream brotli = new BrotliInputStream(new ByteArrayInputStream(in));
final ByteArrayOutputStream result = new ByteArrayOutputStream();
FileUtils.copyToStream(brotli, result);
brotli.close();
result.close();
return result.toByteArray();
}
}

View File

@ -42,10 +42,13 @@ import java.util.zip.Inflater;
public class CompressionZlib implements Compression {
private static boolean USE_ZOPFLI = false;
private static final int COMPRESSION_LEVEL = 9;
// private static final int COMPRESSION_LEVEL = 1;
public byte[] compress(byte[] in) {
if (USE_ZOPFLI) {
return new CompressionZopfliZlib().compress(in);
}
if (in.length == 0) {
return null;
}

View File

@ -33,54 +33,33 @@
*
*
*/
package net.sourceforge.plantuml.webp;
package net.sourceforge.plantuml.code;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import javax.imageio.ImageIO;
import javax.imageio.stream.ImageInputStream;
import net.sourceforge.plantuml.zopfli.Options;
import net.sourceforge.plantuml.zopfli.Options.BlockSplitting;
import net.sourceforge.plantuml.zopfli.Options.OutputFormat;
import net.sourceforge.plantuml.zopfli.Zopfli;
public class Portrait {
public class CompressionZopfliZlib implements Compression {
private final String name;
private final int age;
private final String quote;
private final byte webp[];
public Portrait(String name, int age, String quote, byte webp[]) throws IOException {
this.name = name;
this.quote = quote;
this.age = age;
this.webp = webp;
}
public BufferedImage getBufferedImage() {
try {
final InputStream is = new ByteArrayInputStream(webp);
final ImageInputStream iis = ImageIO.createImageInputStream(is);
final VP8Decoder vp8Decoder = new VP8Decoder();
vp8Decoder.decodeFrame(iis, false);
iis.close();
return vp8Decoder.getFrame().getBufferedImage();
} catch (IOException e) {
public byte[] compress(byte[] in) {
if (in.length == 0) {
return null;
}
int len = in.length * 2;
if (len < 100) {
len = 100;
}
final Zopfli compressor = new Zopfli(len);
final Options options = new Options(OutputFormat.DEFLATE, BlockSplitting.FIRST, 30);
return compressor.compress(options, in).getResult();
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
public String getQuote() {
return quote;
public byte[] decompress(byte[] in) throws IOException {
return new CompressionZlib().decompress(in);
}
}

View File

@ -0,0 +1,69 @@
/* ========================================================================
* PlantUML : a free UML diagram generator
* ========================================================================
*
* (C) Copyright 2009-2017, Arnaud Roques
*
* Project Info: http://plantuml.com
*
* If you like this project or if you find it useful, you can support us at:
*
* http://plantuml.com/patreon (only 1$ per month!)
* http://plantuml.com/paypal
*
* This file is part of PlantUML.
*
* PlantUML is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* PlantUML distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
* License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*
*
* Original Author: Arnaud Roques
*
*
*/
package net.sourceforge.plantuml.code;
public class PairInt {
private final int x;
private final int y;
public PairInt(int x, int y) {
this.x = x;
this.y = y;
}
public PairInt rotate() {
return new PairInt(-y, x);
}
@Override
public String toString() {
return "(" + x + "," + y + ")";
}
public int getX() {
return x;
}
public int getY() {
return y;
}
public PairInt plus(PairInt other) {
return new PairInt(x + other.x, y + other.y);
}
}

View File

@ -0,0 +1,67 @@
/* ========================================================================
* PlantUML : a free UML diagram generator
* ========================================================================
*
* (C) Copyright 2009-2017, Arnaud Roques
*
* Project Info: http://plantuml.com
*
* If you like this project or if you find it useful, you can support us at:
*
* http://plantuml.com/patreon (only 1$ per month!)
* http://plantuml.com/paypal
*
* This file is part of PlantUML.
*
* PlantUML is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* PlantUML distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
* License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*
*
* Original Author: Arnaud Roques
*
*
*/
package net.sourceforge.plantuml.code;
public class Spiral {
private PairInt current = new PairInt(0, 0);
private PairInt direction = new PairInt(1, 0);
private int step = 0;
private int lim = 1;
private int len = 1;
private int cpt = 0;
public PairInt nextPoint() {
final PairInt result = current;
oneStep();
return result;
}
private void oneStep() {
this.current = this.current.plus(this.direction);
step++;
if (step == lim) {
this.direction = this.direction.rotate();
cpt++;
if (cpt == 2) {
cpt = 0;
len++;
}
lim += len;
}
}
}

View File

@ -0,0 +1,65 @@
/* ========================================================================
* PlantUML : a free UML diagram generator
* ========================================================================
*
* (C) Copyright 2009-2017, Arnaud Roques
*
* Project Info: http://plantuml.com
*
* If you like this project or if you find it useful, you can support us at:
*
* http://plantuml.com/patreon (only 1$ per month!)
* http://plantuml.com/paypal
*
* This file is part of PlantUML.
*
* PlantUML is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* PlantUML distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
* License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*
*
* Original Author: Arnaud Roques
*
*
*/
package net.sourceforge.plantuml.code;
public class SpiralOnRectangle {
private final Spiral spiral = new Spiral();
private final int width;
private final int height;
private final PairInt delta;
public SpiralOnRectangle(int width, int height) {
this.width = width;
this.height = height;
this.delta = new PairInt(width / 2, height / 2);
}
private boolean inside(PairInt point) {
final int x = point.getX();
final int y = point.getY();
return x >= 0 && x < width && y >= 0 && y < height;
}
public PairInt nextPoint() {
do {
final PairInt result = spiral.nextPoint().plus(delta);
if (inside(result)) {
return result;
}
} while (true);
}
}

View File

@ -47,6 +47,10 @@ public class TranscoderImpl implements Transcoder {
this(new AsciiEncoder(), new StringCompressorNone(), new CompressionHuffman());
}
public TranscoderImpl(Compression compression) {
this(new AsciiEncoder(), new StringCompressorNone(), compression);
}
public TranscoderImpl(URLEncoder urlEncoder, Compression compression) {
this(urlEncoder, new ArobaseStringCompressor(), compression);
}

View File

@ -39,17 +39,17 @@ import java.io.IOException;
public class TranscoderSmart implements Transcoder {
private final Transcoder oldOne = new TranscoderImpl(new AsciiEncoder(), new CompressionHuffman());
// private final Transcoder oldOne = new TranscoderImpl(new AsciiEncoder(), new CompressionHuffman());
private final Transcoder zlib = new TranscoderImpl(new AsciiEncoder(), new CompressionZlib());
private final Transcoder brotli = new TranscoderImpl(new AsciiEncoder(), new CompressionBrotli());
public String decode(String code) throws IOException {
try {
return zlib.decode(code);
} catch (Exception ex) {
return oldOne.decode(code);
if (code.startsWith("0")) {
return brotli.decode(code.substring(1));
}
return zlib.decode(code);
}
public String encode(String text) throws IOException {
return zlib.encode(text);
}

View File

@ -94,6 +94,9 @@ public class BlocLines implements Iterable<CharSequence> {
}
public CharSequence getFirst499() {
if (lines.size()==0) {
return null;
}
return lines.get(0);
}
@ -229,34 +232,38 @@ public class BlocLines implements Iterable<CharSequence> {
return lines.iterator();
}
@Deprecated
public BlocLines removeComments() {
final List<CharSequence> copy = new ArrayList<CharSequence>();
boolean inComment = false;
for (CharSequence cs : lines) {
if (inComment == false && MyPattern.mtches(cs, CommandMultilinesComment.COMMENT_SINGLE_LINE)) {
continue;
}
if (inComment == false && MyPattern.mtches(cs, CommandMultilinesComment.COMMENT_MULTILINE_START)) {
inComment = true;
continue;
}
if (inComment && MyPattern.mtches(cs, CommandMultilinesComment.COMMENT_MULTILINE_END)) {
inComment = false;
continue;
}
if (inComment == false) {
copy.add(cs);
}
}
return new BlocLines(copy);
return this;
// final List<CharSequence> copy = new ArrayList<CharSequence>();
// boolean inComment = false;
// for (CharSequence cs : lines) {
// if (inComment == false && MyPattern.mtches(cs, CommandMultilinesComment.COMMENT_SINGLE_LINE)) {
// continue;
// }
// if (inComment == false && MyPattern.mtches(cs, CommandMultilinesComment.COMMENT_MULTILINE_START)) {
// inComment = true;
// continue;
// }
// if (inComment && MyPattern.mtches(cs, CommandMultilinesComment.COMMENT_MULTILINE_END)) {
// inComment = false;
// continue;
// }
// if (inComment == false) {
// copy.add(cs);
// }
// }
// return new BlocLines(copy);
}
@Deprecated
public BlocLines removeInnerComments() {
final List<CharSequence> copy = new ArrayList<CharSequence>();
for (CharSequence cs : lines) {
copy.add(MyPattern.removeAll(cs, CommandMultilinesComment.INNER_COMMENT));
}
return new BlocLines(copy);
return this;
// final List<CharSequence> copy = new ArrayList<CharSequence>();
// for (CharSequence cs : lines) {
// copy.add(MyPattern.removeAll(cs, CommandMultilinesComment.INNER_COMMENT));
// }
// return new BlocLines(copy);
}
}

View File

@ -42,7 +42,7 @@ import net.sourceforge.plantuml.core.Diagram;
public class CommandComment extends SingleLineCommand<Diagram> {
public CommandComment() {
private CommandComment() {
super(CommandMultilinesComment.COMMENT_SINGLE_LINE);
}

View File

@ -66,7 +66,11 @@ public abstract class CommandMultilines2<S extends Diagram> implements Command<S
if (isCommandForbidden()) {
return CommandControl.NOT_OK;
}
final boolean result1 = starting.match(StringUtils.trin(lines.getFirst499()));
final CharSequence first = lines.getFirst499();
if (first == null) {
return CommandControl.NOT_OK;
}
final boolean result1 = starting.match(StringUtils.trin(first));
if (result1 == false) {
return CommandControl.NOT_OK;
}

View File

@ -64,7 +64,11 @@ public abstract class CommandMultilines3<S extends Diagram> implements Command<S
if (isCommandForbidden()) {
return CommandControl.NOT_OK;
}
final boolean result1 = starting.match(StringUtils.trin(lines.getFirst499()));
final CharSequence first = lines.getFirst499();
if (first == null) {
return CommandControl.NOT_OK;
}
final boolean result1 = starting.match(StringUtils.trin(first));
if (result1 == false) {
return CommandControl.NOT_OK;
}

View File

@ -44,7 +44,7 @@ public class CommandMultilinesComment extends CommandMultilines<Diagram> {
public static final String COMMENT_SINGLE_LINE = "(?i)^[%s]*([%q].*||/[%q].*[%q]/[%s]*)$";
public static final String INNER_COMMENT = "/[%q].*?[%q]/";
public CommandMultilinesComment() {
private CommandMultilinesComment() {
super(COMMENT_MULTILINE_START);
}

View File

@ -101,7 +101,7 @@ public class CommandSpriteFile extends SingleLineCommand2<UmlDiagram> {
if (isSvg(f.getName())) {
sprite = new SpriteSvg(f);
} else {
sprite = new SpriteImage(ImageIO.read(f));
sprite = new SpriteImage(FileUtils.ImageIO_read(f));
}
}
} catch (IOException e) {

View File

@ -266,8 +266,8 @@ public abstract class UmlDiagramFactory extends PSystemAbstractFactory {
final protected void addCommonCommands(List<Command> cmds) {
cmds.add(new CommandNope());
cmds.add(new CommandComment());
cmds.add(new CommandMultilinesComment());
// cmds.add(new CommandComment());
// cmds.add(new CommandMultilinesComment());
cmds.add(new CommandPragma());
cmds.add(new CommandTitle());
cmds.add(new CommandCaption());

View File

@ -0,0 +1,80 @@
/* ========================================================================
* PlantUML : a free UML diagram generator
* ========================================================================
*
* (C) Copyright 2009-2017, Arnaud Roques
*
* Project Info: http://plantuml.com
*
* If you like this project or if you find it useful, you can support us at:
*
* http://plantuml.com/patreon (only 1$ per month!)
* http://plantuml.com/paypal
*
* This file is part of PlantUML.
*
* PlantUML is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* PlantUML distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
* License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*
*
* Original Author: Arnaud Roques
*
*
*/
package net.sourceforge.plantuml.creole;
import java.awt.geom.Dimension2D;
import java.util.List;
import net.sourceforge.plantuml.Dimension2DDouble;
import net.sourceforge.plantuml.graphic.StringBounder;
import net.sourceforge.plantuml.ugraphic.UGraphic;
import net.sourceforge.plantuml.ugraphic.UTranslate;
public class AtomHorizontalTexts implements Atom {
private final List<Atom> all;
public AtomHorizontalTexts(List<Atom> texts) {
this.all = texts;
}
public Dimension2D calculateDimension(StringBounder stringBounder) {
double width = 0;
double height = 0;
for (Atom text : all) {
final Dimension2D dim = text.calculateDimension(stringBounder);
height = Math.max(height, dim.getHeight());
width += dim.getWidth();
}
return new Dimension2DDouble(width, height);
}
public double getStartingAltitude(StringBounder stringBounder) {
if (all.size() == 0) {
return 0;
}
return all.get(0).getStartingAltitude(stringBounder);
}
public void drawU(UGraphic ug) {
double x = 0;
for (Atom text : all) {
final Dimension2D dim = text.calculateDimension(ug.getStringBounder());
text.drawU(ug.apply(new UTranslate(x, 0)));
x += dim.getWidth();
}
}
}

View File

@ -35,7 +35,6 @@
*/
package net.sourceforge.plantuml.creole;
import java.awt.Font;
import java.awt.geom.Dimension2D;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
@ -50,6 +49,7 @@ import javax.imageio.ImageIO;
import net.sourceforge.plantuml.Dimension2DDouble;
import net.sourceforge.plantuml.FileSystem;
import net.sourceforge.plantuml.FileUtils;
import net.sourceforge.plantuml.code.Base64Coder;
import net.sourceforge.plantuml.graphic.FontConfiguration;
import net.sourceforge.plantuml.graphic.ImgValign;
@ -89,19 +89,19 @@ public class AtomImg implements Atom {
if (f.exists() == false) {
// Check if valid URL
if (src.startsWith("http:") || src.startsWith("https:")) {
final byte image[] = getFile(src);
return build(src, fc, image, scale);
// final byte image[] = getFile(src);
return build(src, fc, new URL(src), scale);
}
return AtomText.create("(File not found: " + f + ")", fc);
return AtomText.create("(File not found: " + f.getCanonicalPath() + ")", fc);
}
if (f.getName().endsWith(".svg")) {
return new AtomImgSvg(new TileImageSvg(f));
}
final BufferedImage read = ImageIO.read(f);
final BufferedImage read = FileUtils.ImageIO_read(f);
if (read == null) {
return AtomText.create("(Cannot decode: " + f + ")", fc);
return AtomText.create("(Cannot decode: " + f.getCanonicalPath() + ")", fc);
}
return new AtomImg(ImageIO.read(f), scale);
return new AtomImg(FileUtils.ImageIO_read(f), scale);
} catch (IOException e) {
return AtomText.create("ERROR " + e.toString(), fc);
}
@ -116,8 +116,16 @@ public class AtomImg implements Atom {
return new AtomImg(read, scale);
}
private static Atom build(String source, final FontConfiguration fc, URL url, double scale) throws IOException {
final BufferedImage read = FileUtils.ImageIO_read(url);
if (read == null) {
return AtomText.create("(Cannot decode: " + source + ")", fc);
}
return new AtomImg(read, scale);
}
// Added by Alain Corbiere
static byte[] getFile(String host) throws IOException {
private static byte[] getFile(String host) throws IOException {
final ByteArrayOutputStream image = new ByteArrayOutputStream();
InputStream input = null;
try {

View File

@ -37,6 +37,7 @@ package net.sourceforge.plantuml.creole;
import java.awt.geom.Dimension2D;
import net.sourceforge.plantuml.Url;
import net.sourceforge.plantuml.graphic.FontConfiguration;
import net.sourceforge.plantuml.graphic.StringBounder;
import net.sourceforge.plantuml.graphic.TextBlock;
@ -49,8 +50,14 @@ public class AtomOpenIcon implements Atom {
private final OpenIcon openIcon;
private final FontConfiguration fontConfiguration;
private final double factor;
private final Url url;
public AtomOpenIcon(OpenIcon openIcon, FontConfiguration fontConfiguration) {
this(openIcon, fontConfiguration, null);
}
public AtomOpenIcon(OpenIcon openIcon, FontConfiguration fontConfiguration, Url url) {
this.url = url;
this.openIcon = openIcon;
this.fontConfiguration = fontConfiguration;
this.factor = fontConfiguration.getSize2D() / 12;
@ -69,7 +76,13 @@ public class AtomOpenIcon implements Atom {
}
public void drawU(UGraphic ug) {
if (url != null) {
ug.startUrl(url);
}
asTextBlock().drawU(ug);
if (url != null) {
ug.closeAction();
}
}
}

View File

@ -41,6 +41,8 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.StringTokenizer;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import net.sourceforge.plantuml.BackSlash;
import net.sourceforge.plantuml.Dimension2DDouble;
@ -50,8 +52,10 @@ import net.sourceforge.plantuml.StringUtils;
import net.sourceforge.plantuml.Url;
import net.sourceforge.plantuml.cucadiagram.Display;
import net.sourceforge.plantuml.graphic.FontConfiguration;
import net.sourceforge.plantuml.graphic.Splitter;
import net.sourceforge.plantuml.graphic.StringBounder;
import net.sourceforge.plantuml.graphic.TextBlockUtils;
import net.sourceforge.plantuml.openiconic.OpenIcon;
import net.sourceforge.plantuml.ugraphic.UChangeColor;
import net.sourceforge.plantuml.ugraphic.UGraphic;
import net.sourceforge.plantuml.ugraphic.UText;
@ -84,14 +88,46 @@ public class AtomText implements Atom {
fontConfiguration = fontConfiguration.hyperlink();
final Display display = Display.getWithNewlines(url.getLabel());
if (display.size() > 1) {
final List<AtomText> all = new ArrayList<AtomText>();
final List<Atom> all = new ArrayList<Atom>();
for (CharSequence s : display.as()) {
all.add(new AtomText(s.toString(), fontConfiguration, url, ZERO, ZERO));
all.add(createAtomText(s.toString(), url, fontConfiguration));
}
return new AtomTexts(all);
return new AtomVerticalTexts(all);
}
return new AtomText(url.getLabel(), fontConfiguration, url, ZERO, ZERO);
return createAtomText(url.getLabel(), url, fontConfiguration);
}
private static Atom createAtomText(final String text, Url url, FontConfiguration fontConfiguration) {
final Pattern p = Pattern.compile(Splitter.openiconPattern);
final Matcher m = p.matcher(text);
final List<Atom> result = new ArrayList<Atom>();
while (m.find()) {
final String val = m.group(1);
final StringBuffer sb = new StringBuffer();
m.appendReplacement(sb, "");
if (sb.length() > 0) {
result.add(new AtomText(sb.toString(), fontConfiguration, url, ZERO, ZERO));
}
final OpenIcon openIcon = OpenIcon.retrieve(val);
if (openIcon != null) {
result.add(new AtomOpenIcon(openIcon, fontConfiguration, url));
}
}
final StringBuffer sb = new StringBuffer();
m.appendTail(sb);
if (sb.length() > 0) {
result.add(new AtomText(sb.toString(), fontConfiguration, url, ZERO, ZERO));
}
if (result.size() == 1) {
return result.get(0);
}
return new AtomHorizontalTexts(result);
}
private static Atom createAtomTextOld(final String text, Url url, FontConfiguration fontConfiguration) {
return new AtomText(text, fontConfiguration, url, ZERO, ZERO);
}
public static AtomText createHeading(String text, FontConfiguration fontConfiguration, int order) {

View File

@ -43,17 +43,17 @@ import net.sourceforge.plantuml.graphic.StringBounder;
import net.sourceforge.plantuml.ugraphic.UGraphic;
import net.sourceforge.plantuml.ugraphic.UTranslate;
public class AtomTexts implements Atom {
private final List<AtomText> all;
public class AtomVerticalTexts implements Atom {
private final List<Atom> all;
public AtomTexts(List<AtomText> texts) {
public AtomVerticalTexts(List<Atom> texts) {
this.all = texts;
}
public Dimension2D calculateDimension(StringBounder stringBounder) {
double width = 0;
double height = 0;
for (AtomText text : all) {
for (Atom text : all) {
final Dimension2D dim = text.calculateDimension(stringBounder);
width = Math.max(width, dim.getWidth());
height += dim.getHeight();
@ -67,7 +67,7 @@ public class AtomTexts implements Atom {
public void drawU(UGraphic ug) {
double y = 0;
for (AtomText text : all) {
for (Atom text : all) {
final Dimension2D dim = text.calculateDimension(ug.getStringBounder());
text.drawU(ug.apply(new UTranslate(0, y)));
y += dim.getHeight();

View File

@ -114,6 +114,13 @@ public class LinkStyle {
return new UStroke(nonZeroThickness());
}
public UStroke muteStroke(UStroke stroke) {
if (type == Type.DASHED || type == Type.DOTTED || type == Type.BOLD) {
return getStroke3();
}
return stroke;
}
private double nonZeroThickness() {
if (thickness == 0) {
return 1;

View File

@ -46,6 +46,10 @@ public class LinkType {
private final LinkHat hat2;
private final LinkMiddleDecor middleDecor;
public boolean isDoubleDecorated() {
return decor1 != LinkDecor.NONE && decor2 != LinkDecor.NONE;
}
public LinkType(LinkDecor decor1, LinkDecor decor2) {
this(LinkHat.NONE, decor1, decor2, LinkHat.NONE);
}

View File

@ -53,6 +53,7 @@ import net.sourceforge.plantuml.cucadiagram.Stereotype;
import net.sourceforge.plantuml.graphic.USymbol;
import net.sourceforge.plantuml.graphic.color.ColorParser;
import net.sourceforge.plantuml.graphic.color.ColorType;
import net.sourceforge.plantuml.graphic.color.Colors;
import net.sourceforge.plantuml.utils.UniqueSequence;
public class CommandPackageWithUSymbol extends SingleLineCommand2<AbstractEntityDiagram> {
@ -93,10 +94,14 @@ public class CommandPackageWithUSymbol extends SingleLineCommand2<AbstractEntity
new RegexLeaf("[%s]*"), //
new RegexLeaf("URL", "(" + UrlBuilder.getRegexp() + ")?"), //
new RegexLeaf("[%s]*"), //
ColorParser.exp1(), //
color().getRegex(), //
new RegexLeaf("[%s]*\\{$"));
}
private static ColorParser color() {
return ColorParser.simpleColor(ColorType.BACK);
}
@Override
protected CommandExecutionResult executeArg(AbstractEntityDiagram diagram, RegexResult arg) {
final String codeRaw = StringUtils.eventuallyRemoveStartingAndEndingDoubleQuote(arg.getLazzy("CODE", 0));
@ -123,11 +128,8 @@ public class CommandPackageWithUSymbol extends SingleLineCommand2<AbstractEntity
if (stereotype != null) {
p.setStereotype(new Stereotype(stereotype, false));
}
final String color = arg.get("COLOR", 0);
if (color != null) {
p.setSpecificColorTOBEREMOVED(ColorType.BACK,
diagram.getSkinParam().getIHtmlColorSet().getColorIfValid(color));
}
final Colors colors = color().getColor(arg, diagram.getSkinParam().getIHtmlColorSet());
p.setColors(colors);
return CommandExecutionResult.ok();
}

View File

@ -46,6 +46,7 @@ import java.util.StringTokenizer;
import net.sourceforge.plantuml.AbstractPSystem;
import net.sourceforge.plantuml.BackSlash;
import net.sourceforge.plantuml.FileFormatOption;
import net.sourceforge.plantuml.code.CompressionBrotli;
import net.sourceforge.plantuml.code.Transcoder;
import net.sourceforge.plantuml.code.TranscoderImpl;
import net.sourceforge.plantuml.core.DiagramDescription;
@ -65,19 +66,19 @@ import net.sourceforge.plantuml.version.PSystemVersion;
public class PSystemDonors extends AbstractPSystem {
public static final String DONORS = "UDfjL4jksp0GtSyfk1RIGoXsxDI_17QQ0jcDvR75c29TKd8ghOBUe421hdk3eaKMHOjiUW7bHXqvbKcb"
+ "9M3058V3zsRUcrX5VnTPkAISh8XrRhJ41AueyijaC35-Qnt4xLLSmj3w8ofXGKjqkKGjPYRL4EkLiM9e"
+ "AA-e-RjUSqGRZXec63oaS-ZBTYCLn3wrsSEYy11A6CgekxI1KOkoSB38QPUI5ZrZTioltxv33iRPYwl6"
+ "GiyegSNS58vWLBmuZsuD4satEmdJ03LcuPQVYXMzHxtYSlPIoLatQ4jcEZ_IrXkOXUZp2YwKtFE5laos"
+ "ZFnu8ZMSkMDg7O28Q0_zAfEvBSK4KxD263L5lqcHqmTn4IdVBbxRaikaCUSuniUuHi_WQTjXfLUyjGdN"
+ "P81BMsxDdTjAJgJuseNDPGNdFdfbO2gJb9GuHQdAa86gGZ3EmOXGlnfXyguW9_h5qYBtKdc-r-OsfoGL"
+ "OuiEFQGDiKI3Zjqrok8GCJPx6Ghb89Ktdh14c0VYRPu8UKQtV7iNoCficygS6eiQrUv4t52EPkTWpWJH"
+ "hiHODgs5WJAsgVVqzo-b3attWb21E5bEawESBBRLRhgUTXavkCHM7dFP0HmhAHQ8AxQEtP1uItf3zaHC"
+ "uwlNYzXBEp8QXjInJCXS9ooHJ5mpwZwBTkmZBJMTPRDCYE1i7of_Zp3pIIXhGKO1ZM4XMHT5Hc9W2ifz"
+ "VHC7Wx0p1ovU3ReAoyPmPtB36bh8p5kG0R6JrqsbaLqTW8wKWlfJ_H2ahn_g7z1BEzOksNZ5yZ08h6Ol"
+ "d9iEd26PzTfIAMOouyQDyD-fCiSrAZ4jdMAFr5_gXwVx-dlpbAW_ru_rp_hnwGF_xldJDpYpL8angeoT"
+ "THxskf4hiLvFIJM7EcWRloA3gHX5F2IxB5XWr_HoA4M5uhdHKibXSKZeSgW_rb-F9M5Wx3cVvyei9SFe"
+ "eyr2dx88J6VmAHwXNeLhxcfOkAtF-PyPyzpDgyhFkpzUfhdf";
public static final String DONORS = "6w8602mIZ6r6h8Vz5iSz4U4e4OD_QwRy4VHnsX9GMiAKM7PtB6kpHqv0K9vJl6yGnOAW0UkI7k_btCRE"
+ "s8BWkQAuWWgGLz6DShx6dP852fGRwsVRI0vl_tyk5zYzA93UUPlo1CFZW6viQeo14x1jzwEoGVz5Tu4M"
+ "y3IwiuP5bpLRFaGClgArQvZPYpGGGYk_WL9IPoX6M28br2viuHIIWn7KMkTrn3FSldvIBrABZLaivJaJ"
+ "oArsSJJV_h6thcJxSMQ9e1_gWAm3E803vKvE64T-i57vrI11PGwwiQcIcITkY8X10xtnG-cKb9AApE78"
+ "H1Lm1KY4_1aZ08z7DNLoDZSDA5aoM_Gi2UhKUk1kZfTfARKl6awI0m5Ewe1M2UG_q1rwxpBxIuDdNGmn"
+ "Kz_9t6JpK6n4TF7zCT2db1lwv0b0xSoSTREfNKggSUcllJx6Ne0ebffzb3VzZNUsO5x_FOHql5Y0yW8w"
+ "rpiYviyVryb29aHpwVQ22-VYoTL5GDeu31O-n9BLr8TtCM98cgSuYt2utg3QY40dLrrS1gwkbSnNErTW"
+ "cgN5zLkVXjNh8DSarUPzYrRIYwNiVuHtDMiP3jhlOapN9ObmpJXPTGUBBWB3eEs1i99SIBNDzLFTl7_B"
+ "Flj9S6z396653P4wKDVJb6yTLX5lLBhKn02m_f2eTrH13_4WgmFeCgYymjCHTZjSBTEdZl7QQKqUmcuC"
+ "wgiwKxdZFZoKliCmAOzcTTNs5kS0BgDWBZ_RsBwAO_KCxx4NeNbE1iOjFUY1z1rMrhNxI-xR0c5ciHRS"
+ "BMI_7hxpvw6RVv_-B1gvkl-v_WzpLJn-9zIkjvJbiAJRctLPnVSYgWZGEq6xG7LcF0JiEvCJrJb2vJU3"
+ "6V3m98cmFhYuFh7WDX2rPMLdAJP4R4UixWCjoG-LJXfLrC2IzTxkf3mZMbIptvntOOx7Ogb2hmMKowg2"
+ "QpGGzff2rVGvMLHSSW00";
@Override
final protected ImageData exportDiagramNow(OutputStream os, int num, FileFormatOption fileFormat, long seed)
@ -126,7 +127,7 @@ public class PSystemDonors extends AbstractPSystem {
private List<String> getDonors() throws IOException {
final List<String> lines = new ArrayList<String>();
final Transcoder t = new TranscoderImpl();
final Transcoder t = new TranscoderImpl(new CompressionBrotli());
final String s = t.decode(DONORS).replace('*', '.');
final StringTokenizer st = new StringTokenizer(s, BackSlash.NEWLINE);
while (st.hasMoreTokens()) {

View File

@ -1,165 +0,0 @@
/* ========================================================================
* PlantUML : a free UML diagram generator
* ========================================================================
*
* (C) Copyright 2009-2017, Arnaud Roques
*
* Project Info: http://plantuml.com
*
* If you like this project or if you find it useful, you can support us at:
*
* http://plantuml.com/patreon (only 1$ per month!)
* http://plantuml.com/paypal
*
* This file is part of PlantUML.
*
* PlantUML is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* PlantUML distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
* License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*
*
* Original Author: Arnaud Roques
*
*
*/
package net.sourceforge.plantuml.graphic;
public class DateEventUtils {
// private static final String PARIS = "A thought for those who died in Paris the 13th November 2015.";
//
// private static TextBlock addEvent(final TextBlock textBlock, final HtmlColor color) {
// try {
// final String today = new SimpleDateFormat("MM-dd", Locale.US).format(new Date());
// if ("11-05".equals(today)) {
// final List<String> asList = Arrays.asList("<u>November 5th, 1955",
// "Doc Brown's discovery of the Flux Capacitor, that makes time-travel possible.");
// return TextBlockUtils.mergeTB(textBlock, getComment(asList, color), HorizontalAlignment.LEFT);
// } else if ("08-29".equals(today)) {
// final List<String> asList = Arrays.asList("<u>August 29th, 1997",
// "Skynet becomes self-aware at 02:14 AM Eastern Time.");
// return TextBlockUtils.mergeTB(textBlock, getComment(asList, color), HorizontalAlignment.LEFT);
// } else if ("06-29".equals(today)) {
// final List<String> asList = Arrays.asList("<u>June 29th, 1975",
// "\"It was the first time in history that anyone had typed",
// "a character on a keyboard and seen it show up on their",
// "own computer's screen right in front of them.\"", "\t\t\t\t\t\t\t\t\t\t<i>Steve Wozniak");
// return TextBlockUtils.mergeTB(textBlock, getComment(asList, color), HorizontalAlignment.LEFT);
// } else if ("01-07".equals(today) || ("01-08".equals(today) && getDayOfWeek() == Calendar.MONDAY)) {
// return addCharlie(textBlock);
// } else if ("11-13".equals(today) || ("11-14".equals(today) && getDayOfWeek() == Calendar.MONDAY)) {
// return addMemorial(textBlock, color);
// }
// } catch (Throwable t) {
// Log.debug("Error " + t);
// }
// return textBlock;
// }
//
// private synchronized static int getDayOfWeek() {
// return Calendar.getInstance().get(Calendar.DAY_OF_WEEK);
// }
//
// private static TextBlock addMemorial(TextBlock textBlock, HtmlColor color) {
// final Portrait portrait = Portraits.getOne();
// if (portrait == null) {
// return textBlock;
// }
// final BufferedImage im = portrait.getBufferedImage();
// if (im == null) {
// return textBlock;
// }
//
// final String name = portrait.getName();
// final String quote = portrait.getQuote();
// final String age = "" + portrait.getAge() + " years old";
// final UFont font12 = new UFont("SansSerif", Font.BOLD, 12);
// TextBlock comment = Display.create(name, age, quote).create(
// new FontConfiguration(font12, color, HtmlColorUtils.BLUE, true), HorizontalAlignment.LEFT,
// new SpriteContainerEmpty());
// comment = TextBlockUtils.withMinWidth(TextBlockUtils.withMargin(comment, 4, 4), 800, HorizontalAlignment.LEFT);
//
// final TextBlock bottom0 = getComment(Arrays.asList(PARIS), color);
// final TextBlock bottom1 = new AbstractTextBlock() {
// private double margin = 10;
//
// public void drawU(UGraphic ug) {
// ug = ug.apply(new UTranslate(0, margin));
// ug.draw(new UImage(im));
// if (ug instanceof LimitFinder) {
// return;
// }
// Portraits.nextOne();
// }
//
// public Dimension2D calculateDimension(StringBounder stringBounder) {
// return new Dimension2DDouble(im.getWidth(), margin + im.getHeight());
// }
// };
// final TextBlock bottom = TextBlockUtils.mergeTB(bottom0,
// TextBlockUtils.mergeLR(bottom1, comment, VerticalAlignment.CENTER), HorizontalAlignment.LEFT);
// final TextBlock mergeTB = TextBlockUtils.mergeTB(textBlock, bottom, HorizontalAlignment.LEFT);
// return addMajesty(mergeTB, color);
// }
//
// public static TextBlock addMajesty(TextBlock block, HtmlColor color) {
// final UFont font12 = new UFont("SansSerif", Font.BOLD, 12);
// final String arabic1 = "<size:16>\u0625\u0646 \u0627\u0644\u0625\u0631\u0647\u0627\u0628\u064A\u064A\u0646 \u0628\u0627\u0633\u0645 \u0627\u0644\u0625\u0633\u0644\u0627\u0645 \u0644\u064A\u0633\u0648\u0627 \u0645\u0633\u0644\u0645\u064A\u0646\u060C \u0648\u0644\u0627 \u064A\u0631\u0628\u0637\u0647\u0645 \u0628\u0627\u0644\u0625\u0633\u0644\u0627\u0645 \u0625\u0644\u0627 \u0627\u0644\u062F\u0648\u0627\u0641\u0639 \u0627\u0644\u062A\u064A \u064A\u0631\u0643\u0628\u0648\u0646 \u0639\u0644\u064A\u0647\u0627 \u0644\u062A\u0628\u0631\u064A\u0631 \u062C\u0631\u0627\u0626\u0645\u0647\u0645 \u0648\u062D\u0645\u0627\u0642\u0627\u062A\u0647\u0645.";
// final String arabic2 = "<size:16>\u0641\u0647\u0645 \u0642\u0648\u0645 \u0636\u0627\u0644\u0648\u0646\u060C \u0645\u0635\u064A\u0631\u0647\u0645 \u062C\u0647\u0646\u0645 \u062E\u0627\u0644\u062F\u064A\u0646 \u0641\u064A\u0647\u0627 \u0623\u0628\u062F\u0627.";
// final String english1 = "<size:10>Those who engage in terrorism, in the name of Islam, are not Muslims.";
// final String english2 = "<size:10>Their only link to Islam is the pretexts they use to justify their crimes and their folly.";
// final String english3 = "<size:10>They have strayed from the right path, and their fate is to dwell forever in hell.";
// final TextBlock arabic = Display
// .create(" ",
// arabic1,
// arabic2,
// "<size:16>\u0635\u0627\u062D\u0628 \u0627\u0644\u062C\u0644\u0627\u0644\u0629 \u0627\u0644\u0645\u0644\u0643 \u0645\u062D\u0645\u062F \u0627\u0644\u0633\u0627\u062F\u0633 \u0623\u0645\u064A\u0631 \u0627\u0644\u0645\u0624\u0645\u0646\u064A\u0646 \u0646\u0635\u0631\u0647 \u0627\u0644\u0644\u0647")
// .create(new FontConfiguration(font12, color, HtmlColorUtils.BLUE, true), HorizontalAlignment.RIGHT,
// new SpriteContainerEmpty());
// final TextBlock english = Display.create(english1, english2, english3,
// "<size:10>-- His Majesty the King Mohammed the Sixth, Commander of the Faithful").create(
// new FontConfiguration(font12, color, HtmlColorUtils.BLUE, true), HorizontalAlignment.LEFT,
// new SpriteContainerEmpty());
// return TextBlockUtils.mergeTB(block, TextBlockUtils.mergeTB(arabic, english, HorizontalAlignment.LEFT),
// HorizontalAlignment.LEFT);
// }
//
// private static TextBlock addCharlie(TextBlock textBlock) {
// final TextBlock charlie = new AbstractTextBlock() {
// private final BufferedImage charlie = PSystemVersion.getCharlieImage();
//
// public void drawU(UGraphic ug) {
// ug.draw(new UImage(charlie));
// }
//
// public Dimension2D calculateDimension(StringBounder stringBounder) {
// return new Dimension2DDouble(charlie.getWidth(), charlie.getHeight());
// }
// };
// return TextBlockUtils.mergeTB(charlie, textBlock, HorizontalAlignment.LEFT);
//
// }
//
// public static TextBlock getComment(final List<String> asList, HtmlColor color) {
// final UFont font = UFont.sansSerif(14).bold();
// TextBlock comment = Display.create(asList).create(
// new FontConfiguration(font, color, HtmlColorUtils.BLUE, true), HorizontalAlignment.LEFT,
// new SpriteContainerEmpty());
// comment = TextBlockUtils.withMargin(comment, 4, 4);
// comment = new SimpleTextBlockBordered(comment, color);
// comment = TextBlockUtils.withMargin(comment, 10, 10);
// return comment;
// }
}

View File

@ -69,4 +69,8 @@ public enum HorizontalAlignment {
return result;
}
public String getGraphVizValue() {
return toString().substring(0, 1).toLowerCase();
}
}

View File

@ -47,6 +47,7 @@ import java.net.URLConnection;
import javax.imageio.ImageIO;
import net.sourceforge.plantuml.FileSystem;
import net.sourceforge.plantuml.FileUtils;
import net.sourceforge.plantuml.StringUtils;
import net.sourceforge.plantuml.command.regex.Matcher2;
import net.sourceforge.plantuml.command.regex.MyPattern;
@ -102,8 +103,9 @@ public class Img implements HtmlCommand {
if (f.exists() == false) {
// Check if valid URL
if (src.startsWith("http:") || src.startsWith("https:")) {
final byte image[] = getFile(src);
final BufferedImage read = ImageIO.read(new ByteArrayInputStream(image));
// final byte image[] = getFile(src);
// final BufferedImage read = ImageIO.read(new ByteArrayInputStream(image));
final BufferedImage read = FileUtils.ImageIO_read(new URL(src));
if (read == null) {
return new Text("(Cannot decode: " + src + ")");
}
@ -114,11 +116,11 @@ public class Img implements HtmlCommand {
if (f.getName().endsWith(".svg")) {
return new Img(new TileImageSvg(f));
}
final BufferedImage read = ImageIO.read(f);
final BufferedImage read = FileUtils.ImageIO_read(f);
if (read == null) {
return new Text("(Cannot decode: " + f + ")");
}
return new Img(new TileImage(ImageIO.read(f), valign, vspace));
return new Img(new TileImage(FileUtils.ImageIO_read(f), valign, vspace));
} catch (IOException e) {
return new Text("ERROR " + e.toString());
}

View File

@ -0,0 +1,64 @@
/* ========================================================================
* PlantUML : a free UML diagram generator
* ========================================================================
*
* (C) Copyright 2009-2017, Arnaud Roques
*
* Project Info: http://plantuml.com
*
* If you like this project or if you find it useful, you can support us at:
*
* http://plantuml.com/patreon (only 1$ per month!)
* http://plantuml.com/paypal
*
* This file is part of PlantUML.
*
* PlantUML is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* PlantUML distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
* License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*
*
* Original Author: Arnaud Roques
*
*
*/
package net.sourceforge.plantuml.graphic;
import net.sourceforge.plantuml.ugraphic.UChange;
import net.sourceforge.plantuml.ugraphic.UGraphic;
import net.sourceforge.plantuml.ugraphic.UShape;
import net.sourceforge.plantuml.ugraphic.UText;
public class UGraphicAddAriaLabel extends UGraphicDelegator {
private final String ariaLabel;
public UGraphicAddAriaLabel(UGraphic ug, String ariaLabel) {
super(ug);
this.ariaLabel = ariaLabel;
}
public UGraphic apply(UChange change) {
return new UGraphicAddAriaLabel(getUg().apply(change), ariaLabel);
}
@Override
public void draw(UShape shape) {
if (shape instanceof UText) {
shape = ((UText) shape).withAriaLabel(ariaLabel);
}
super.draw(shape);
}
}

View File

@ -126,8 +126,8 @@ public abstract class USymbol {
public abstract TextBlock asSmall(TextBlock name, TextBlock label, TextBlock stereotype, SymbolContext symbolContext);
public abstract TextBlock asBig(TextBlock label, TextBlock stereotype, double width, double height,
SymbolContext symbolContext);
public abstract TextBlock asBig(TextBlock label, HorizontalAlignment labelAlignment, TextBlock stereotype,
double width, double height, SymbolContext symbolContext);
static class Margin {
private final double x1;

View File

@ -88,13 +88,14 @@ class USymbolArtifact extends USymbol {
private Margin getMargin() {
return new Margin(10, 10 + 10, 10 + 3, 10);
}
public boolean manageHorizontalLine() {
return true;
}
public TextBlock asSmall(TextBlock name, final TextBlock label, final TextBlock stereotype, final SymbolContext symbolContext) {
@Override
public TextBlock asSmall(TextBlock name, final TextBlock label, final TextBlock stereotype,
final SymbolContext symbolContext) {
return new AbstractTextBlock() {
public void drawU(UGraphic ug) {
@ -115,8 +116,9 @@ class USymbolArtifact extends USymbol {
};
}
public TextBlock asBig(final TextBlock title, final TextBlock stereotype, final double width, final double height,
final SymbolContext symbolContext) {
@Override
public TextBlock asBig(final TextBlock title, HorizontalAlignment labelAlignment, final TextBlock stereotype,
final double width, final double height, final SymbolContext symbolContext) {
return new AbstractTextBlock() {
public void drawU(UGraphic ug) {

View File

@ -44,19 +44,18 @@ import net.sourceforge.plantuml.ugraphic.URectangle;
import net.sourceforge.plantuml.ugraphic.UTranslate;
class USymbolCard extends USymbol {
private final SkinParameter skinParameter;
public USymbolCard(SkinParameter skinParameter) {
this.skinParameter = skinParameter;
}
@Override
public SkinParameter getSkinParameter() {
return skinParameter;
}
private void drawRect(UGraphic ug, double width, double height, boolean shadowing, double top) {
final URectangle shape = new URectangle(width, height);
if (shadowing) {
@ -72,7 +71,9 @@ class USymbolCard extends USymbol {
return new Margin(10, 10, 3, 3);
}
public TextBlock asSmall(TextBlock name, final TextBlock label, final TextBlock stereotype, final SymbolContext symbolContext) {
@Override
public TextBlock asSmall(TextBlock name, final TextBlock label, final TextBlock stereotype,
final SymbolContext symbolContext) {
return new AbstractTextBlock() {
public void drawU(UGraphic ug) {
@ -92,8 +93,9 @@ class USymbolCard extends USymbol {
};
}
public TextBlock asBig(final TextBlock title, final TextBlock stereotype, final double width, final double height,
final SymbolContext symbolContext) {
@Override
public TextBlock asBig(final TextBlock title, HorizontalAlignment labelAlignment, final TextBlock stereotype,
final double width, final double height, final SymbolContext symbolContext) {
return new AbstractTextBlock() {
public void drawU(UGraphic ug) {

View File

@ -51,7 +51,6 @@ class USymbolCloud extends USymbol {
return SkinParameter.CLOUD;
}
private void drawCloud(UGraphic ug, double width, double height, boolean shadowing) {
final UPath shape = getSpecificFrontierForCloud(width, height);
if (shadowing) {
@ -90,7 +89,9 @@ class USymbolCloud extends USymbol {
return new Margin(10, 10, 10, 10);
}
public TextBlock asSmall(TextBlock name, final TextBlock label, final TextBlock stereotype, final SymbolContext symbolContext) {
@Override
public TextBlock asSmall(TextBlock name, final TextBlock label, final TextBlock stereotype,
final SymbolContext symbolContext) {
return new AbstractTextBlock() {
public void drawU(UGraphic ug) {
@ -111,8 +112,9 @@ class USymbolCloud extends USymbol {
};
}
public TextBlock asBig(final TextBlock title, final TextBlock stereotype, final double width, final double height,
final SymbolContext symbolContext) {
@Override
public TextBlock asBig(final TextBlock title, HorizontalAlignment labelAlignment, final TextBlock stereotype,
final double width, final double height, final SymbolContext symbolContext) {
return new AbstractTextBlock() {
public void drawU(UGraphic ug) {
@ -132,11 +134,10 @@ class USymbolCloud extends USymbol {
}
};
}
@Override
public boolean manageHorizontalLine() {
return true;
}
}

View File

@ -83,6 +83,7 @@ class USymbolCollections extends USymbol {
return 4;
}
@Override
public TextBlock asSmall(TextBlock name, final TextBlock label, final TextBlock stereotype,
final SymbolContext symbolContext) {
return new AbstractTextBlock() {
@ -107,8 +108,9 @@ class USymbolCollections extends USymbol {
};
}
public TextBlock asBig(final TextBlock title, final TextBlock stereotype, final double width, final double height,
final SymbolContext symbolContext) {
@Override
public TextBlock asBig(final TextBlock title, HorizontalAlignment labelAlignment, final TextBlock stereotype,
final double width, final double height, final SymbolContext symbolContext) {
return new AbstractTextBlock() {
public void drawU(UGraphic ug) {
final Dimension2D dim = calculateDimension(ug.getStringBounder());

View File

@ -72,6 +72,7 @@ class USymbolComponent1 extends USymbol {
return new Margin(10, 10, 10, 10);
}
@Override
public TextBlock asSmall(TextBlock name, final TextBlock label, final TextBlock stereotype,
final SymbolContext symbolContext) {
return new AbstractTextBlock() {
@ -95,8 +96,9 @@ class USymbolComponent1 extends USymbol {
};
}
public TextBlock asBig(final TextBlock title, TextBlock stereotype, final double width, final double height,
final SymbolContext symbolContext) {
@Override
public TextBlock asBig(final TextBlock title, HorizontalAlignment labelAlignment, final TextBlock stereotype,
final double width, final double height, final SymbolContext symbolContext) {
throw new UnsupportedOperationException();
}

View File

@ -75,6 +75,7 @@ class USymbolComponent2 extends USymbol {
return new Margin(10 + 5, 20 + 5, 15 + 5, 5 + 5);
}
@Override
public TextBlock asSmall(TextBlock name, final TextBlock label, final TextBlock stereotype,
final SymbolContext symbolContext) {
return new AbstractTextBlock() {
@ -99,8 +100,9 @@ class USymbolComponent2 extends USymbol {
};
}
public TextBlock asBig(final TextBlock title, final TextBlock stereotype, final double width, final double height,
final SymbolContext symbolContext) {
@Override
public TextBlock asBig(final TextBlock title, HorizontalAlignment labelAlignment, final TextBlock stereotype,
final double width, final double height, final SymbolContext symbolContext) {
return new AbstractTextBlock() {
public void drawU(UGraphic ug) {

View File

@ -52,8 +52,6 @@ class USymbolDatabase extends USymbol {
return SkinParameter.DATABASE;
}
private void drawDatabase(UGraphic ug, double width, double height, boolean shadowing) {
final UPath shape = new UPath();
if (shadowing) {
@ -114,7 +112,9 @@ class USymbolDatabase extends USymbol {
return new Margin(10, 10, 24, 5);
}
public TextBlock asSmall(TextBlock name, final TextBlock label, final TextBlock stereotype, final SymbolContext symbolContext) {
@Override
public TextBlock asSmall(TextBlock name, final TextBlock label, final TextBlock stereotype,
final SymbolContext symbolContext) {
return new AbstractTextBlock() {
public void drawU(UGraphic ug) {
@ -135,8 +135,9 @@ class USymbolDatabase extends USymbol {
};
}
public TextBlock asBig(final TextBlock title, final TextBlock stereotype, final double width, final double height,
final SymbolContext symbolContext) {
@Override
public TextBlock asBig(final TextBlock title, HorizontalAlignment labelAlignment, final TextBlock stereotype,
final double width, final double height, final SymbolContext symbolContext) {
return new AbstractTextBlock() {
public void drawU(UGraphic ug) {

View File

@ -80,6 +80,7 @@ class USymbolFile extends USymbol {
return new Margin(10, 10, 10, 10);
}
@Override
public TextBlock asSmall(TextBlock name, final TextBlock label, final TextBlock stereotype,
final SymbolContext symbolContext) {
return new AbstractTextBlock() {
@ -102,8 +103,9 @@ class USymbolFile extends USymbol {
};
}
public TextBlock asBig(final TextBlock title, final TextBlock stereotype, final double width, final double height,
final SymbolContext symbolContext) {
@Override
public TextBlock asBig(final TextBlock title, HorizontalAlignment labelAlignment, final TextBlock stereotype,
final double width, final double height, final SymbolContext symbolContext) {
return new AbstractTextBlock() {
public void drawU(UGraphic ug) {

View File

@ -105,6 +105,7 @@ public class USymbolFolder extends USymbol {
return new Margin(10, 10 + 10, 10 + 3, 10);
}
@Override
public TextBlock asSmall(final TextBlock name, final TextBlock label, final TextBlock stereotype,
final SymbolContext symbolContext) {
if (name == null) {
@ -133,8 +134,9 @@ public class USymbolFolder extends USymbol {
};
}
public TextBlock asBig(final TextBlock title, final TextBlock stereotype, final double width, final double height,
final SymbolContext symbolContext) {
@Override
public TextBlock asBig(final TextBlock title, HorizontalAlignment labelAlignment, final TextBlock stereotype,
final double width, final double height, final SymbolContext symbolContext) {
return new AbstractTextBlock() {
public void drawU(UGraphic ug) {

View File

@ -94,6 +94,7 @@ class USymbolFrame extends USymbol {
return new Margin(10 + 5, 20 + 5, 15 + 5, 5 + 5);
}
@Override
public TextBlock asSmall(TextBlock name, final TextBlock label, final TextBlock stereotype,
final SymbolContext symbolContext) {
return new AbstractTextBlock() {
@ -116,8 +117,9 @@ class USymbolFrame extends USymbol {
};
}
public TextBlock asBig(final TextBlock title, final TextBlock stereotype, final double width, final double height,
final SymbolContext symbolContext) {
@Override
public TextBlock asBig(final TextBlock title, HorizontalAlignment labelAlignment, final TextBlock stereotype,
final double width, final double height, final SymbolContext symbolContext) {
return new AbstractTextBlock() {
public void drawU(UGraphic ug) {

View File

@ -109,6 +109,7 @@ class USymbolNode extends USymbol {
return new Margin(10 + 5, 20 + 5, 15 + 5, 5 + 5);
}
@Override
public TextBlock asSmall(TextBlock name, final TextBlock label, final TextBlock stereotype,
final SymbolContext symbolContext) {
return new AbstractTextBlock() {
@ -131,8 +132,9 @@ class USymbolNode extends USymbol {
};
}
public TextBlock asBig(final TextBlock title, final TextBlock stereotype, final double width, final double height,
final SymbolContext symbolContext) {
@Override
public TextBlock asBig(final TextBlock title, HorizontalAlignment labelAlignment, final TextBlock stereotype,
final double width, final double height, final SymbolContext symbolContext) {
return new AbstractTextBlock() {
public void drawU(UGraphic ug) {

View File

@ -127,6 +127,7 @@ class USymbolQueue extends USymbol {
return new Margin(5, 15, 5, 5);
}
@Override
public TextBlock asSmall(TextBlock name, final TextBlock label, final TextBlock stereotype,
final SymbolContext symbolContext) {
return new AbstractTextBlock() {
@ -150,8 +151,9 @@ class USymbolQueue extends USymbol {
};
}
public TextBlock asBig(final TextBlock title, final TextBlock stereotype, final double width, final double height,
final SymbolContext symbolContext) {
@Override
public TextBlock asBig(final TextBlock title, HorizontalAlignment labelAlignment, final TextBlock stereotype,
final double width, final double height, final SymbolContext symbolContext) {
throw new UnsupportedOperationException();
// return new TextBlock() {
//

View File

@ -76,6 +76,7 @@ class USymbolRect extends USymbol {
return new Margin(10, 10, 10, 10);
}
@Override
public TextBlock asSmall(TextBlock name, final TextBlock label, final TextBlock stereotype,
final SymbolContext symbolContext) {
return new AbstractTextBlock() {
@ -99,8 +100,9 @@ class USymbolRect extends USymbol {
};
}
public TextBlock asBig(final TextBlock title, final TextBlock stereotype, final double width, final double height,
final SymbolContext symbolContext) {
@Override
public TextBlock asBig(final TextBlock title, final HorizontalAlignment labelAlignment, final TextBlock stereotype,
final double width, final double height, final SymbolContext symbolContext) {
return new AbstractTextBlock() {
public void drawU(UGraphic ug) {
final Dimension2D dim = calculateDimension(ug.getStringBounder());
@ -119,7 +121,14 @@ class USymbolRect extends USymbol {
}
stereotype.drawU(ug.apply(new UTranslate(posStereoX, posStereoY)));
final Dimension2D dimTitle = title.calculateDimension(ug.getStringBounder());
final double posTitle = (width - dimTitle.getWidth()) / 2;
final double posTitle;
if (labelAlignment == HorizontalAlignment.LEFT) {
posTitle = 3;
} else if (labelAlignment == HorizontalAlignment.RIGHT) {
posTitle = width - dimTitle.getWidth() - 3;
} else {
posTitle = (width - dimTitle.getWidth()) / 2;
}
title.drawU(ug.apply(new UTranslate(posTitle, 2 + dimStereo.getHeight())));
}

View File

@ -43,7 +43,9 @@ import net.sourceforge.plantuml.ugraphic.UTranslate;
abstract class USymbolSimpleAbstract extends USymbol {
public TextBlock asSmall(TextBlock name, final TextBlock label, final TextBlock stereotype, final SymbolContext symbolContext) {
@Override
public TextBlock asSmall(TextBlock name, final TextBlock label, final TextBlock stereotype,
final SymbolContext symbolContext) {
if (stereotype == null) {
throw new IllegalArgumentException();
}
@ -79,8 +81,9 @@ abstract class USymbolSimpleAbstract extends USymbol {
abstract protected TextBlock getDrawing(final SymbolContext symbolContext);
public TextBlock asBig(final TextBlock title, TextBlock stereotype, final double width, final double height,
final SymbolContext symbolContext) {
@Override
public TextBlock asBig(final TextBlock title, HorizontalAlignment labelAlignment, TextBlock stereotype,
final double width, final double height, final SymbolContext symbolContext) {
throw new UnsupportedOperationException();
}

View File

@ -75,6 +75,7 @@ class USymbolStack extends USymbol {
return new Margin(25, 25, 10, 10);
}
@Override
public TextBlock asSmall(TextBlock name, final TextBlock label, final TextBlock stereotype,
final SymbolContext symbolContext) {
return new AbstractTextBlock() {
@ -98,8 +99,9 @@ class USymbolStack extends USymbol {
};
}
public TextBlock asBig(final TextBlock title, final TextBlock stereotype, final double width, final double height,
final SymbolContext symbolContext) {
@Override
public TextBlock asBig(final TextBlock title, HorizontalAlignment labelAlignment, final TextBlock stereotype,
final double width, final double height, final SymbolContext symbolContext) {
throw new UnsupportedOperationException();
}

View File

@ -63,7 +63,9 @@ class USymbolStorage extends USymbol {
return new Margin(10, 10, 10, 10);
}
public TextBlock asSmall(TextBlock name, final TextBlock label, final TextBlock stereotype, final SymbolContext symbolContext) {
@Override
public TextBlock asSmall(TextBlock name, final TextBlock label, final TextBlock stereotype,
final SymbolContext symbolContext) {
return new AbstractTextBlock() {
public void drawU(UGraphic ug) {
@ -84,8 +86,9 @@ class USymbolStorage extends USymbol {
};
}
public TextBlock asBig(final TextBlock title, final TextBlock stereotype, final double width, final double height,
final SymbolContext symbolContext) {
@Override
public TextBlock asBig(final TextBlock title, HorizontalAlignment labelAlignment, final TextBlock stereotype,
final double width, final double height, final SymbolContext symbolContext) {
return new AbstractTextBlock() {
public void drawU(UGraphic ug) {
@ -106,11 +109,10 @@ class USymbolStorage extends USymbol {
}
};
}
@Override
public boolean manageHorizontalLine() {
return true;
}
}

View File

@ -47,13 +47,15 @@ class USymbolTogether extends USymbol {
return SkinParameter.STORAGE;
}
@Override
public TextBlock asSmall(TextBlock name, final TextBlock label, final TextBlock stereotype,
final SymbolContext symbolContext) {
return TextBlockUtils.empty(10, 10);
}
public TextBlock asBig(final TextBlock title, final TextBlock stereotype, final double width, final double height,
final SymbolContext symbolContext) {
@Override
public TextBlock asBig(final TextBlock title, HorizontalAlignment labelAlignment, final TextBlock stereotype,
final double width, final double height, final SymbolContext symbolContext) {
return new AbstractTextBlock() {
public void drawU(UGraphic ug) {

View File

@ -239,4 +239,11 @@ public class Colors {
return shadowing;
}
public UStroke muteStroke(UStroke stroke) {
if (lineStyle == null) {
return stroke;
}
return lineStyle.muteStroke(stroke);
}
}

View File

@ -67,7 +67,20 @@ public class Defines implements Truth {
}
public static Defines createEmpty() {
return new Defines();
return createEmpty(null);
}
public static Defines createEmpty(String filename) {
final Defines result = new Defines();
if (filename != null) {
result.overrideFilename(filename);
}
return result;
}
public void overrideFilename(String filename) {
environment.put("filename", filename);
environment.put("filenameNoExtension", nameNoExtension(filename));
}
public void importFrom(Defines other) {
@ -85,16 +98,15 @@ public class Defines implements Truth {
if (file == null) {
throw new IllegalArgumentException();
}
final Defines result = createEmpty();
final Defines result = createEmpty(file.getName());
result.environment.put("filedate", new Date(file.lastModified()).toString());
result.environment.put("filename", file.getName());
result.environment.put("filenameNoExtension", nameNoExtension(file));
// result.environment.put("filename", file.getName());
// result.environment.put("filenameNoExtension", nameNoExtension(file));
result.environment.put("dirpath", file.getAbsoluteFile().getParentFile().getAbsolutePath().replace('\\', '/'));
return result;
}
private static String nameNoExtension(File file) {
final String name = file.getName();
private static String nameNoExtension(String name) {
final int x = name.lastIndexOf('.');
if (x == -1) {
return name;

View File

@ -59,6 +59,7 @@ public class Preprocessor implements ReadLine {
private static final String ARG = "(?:\\(" + ID_ARG + "(?:," + ID_ARG + ")*?\\))?";
private static final Pattern2 definePattern = MyPattern.cmpile("^[%s]*!define[%s]+(" + ID + ARG + ")"
+ "(?:[%s]+(.*))?$");
private static final Pattern2 filenamePattern = MyPattern.cmpile("^[%s]*!filename[%s]+(.+)$");
private static final Pattern2 undefPattern = MyPattern.cmpile("^[%s]*!undef[%s]+(" + ID + ")$");
private static final Pattern2 definelongPattern = MyPattern.cmpile("^[%s]*!definelong[%s]+(" + ID + ARG + ")");
private static final Pattern2 enddefinelongPattern = MyPattern.cmpile("^[%s]*" + END_DEFINE_LONG + "[%s]*$");
@ -103,7 +104,11 @@ public class Preprocessor implements ReadLine {
this.defines.restoreState();
}
Matcher2 m = definePattern.matcher(s);
Matcher2 m = filenamePattern.matcher(s);
if (m.find()) {
return manageFilename(m);
}
m = definePattern.matcher(s);
if (m.find()) {
return manageDefine(m, s.toString().trim().endsWith("()"));
}
@ -170,14 +175,20 @@ public class Preprocessor implements ReadLine {
if (read == null) {
return null;
}
def.add(read.toString2());
if (enddefinelongPattern.matcher(read).find()) {
defines.define(group1, def, emptyParentheses);
return this.readLine();
}
def.add(read.toString2());
}
}
private CharSequence2 manageFilename(Matcher2 m) throws IOException {
final String group1 = m.group(1);
this.defines.overrideFilename(group1);
return this.readLine();
}
private CharSequence2 manageDefine(Matcher2 m, boolean emptyParentheses) throws IOException {
final String group1 = m.group(1);
final String group2 = m.group(2);

View File

@ -67,6 +67,7 @@ public class PreprocessorInclude implements ReadLine {
private static final Pattern2 includeDefPattern = MyPattern.cmpile("^[%s]*!includedef[%s]+[%g]?([^%g]+)[%g]?$");
private static final Pattern2 includePattern = MyPattern.cmpile("^[%s]*!include[%s]+[%g]?([^%g]+)[%g]?$");
private static final Pattern2 includePatternStdlib = MyPattern.cmpile("^[%s]*!include[%s]+(\\<[^%g]+\\>)$");
private static final Pattern2 includeManyPattern = MyPattern.cmpile("^[%s]*!include_many[%s]+[%g]?([^%g]+)[%g]?$");
private static final Pattern2 includeURLPattern = MyPattern.cmpile("^[%s]*!includeurl[%s]+[%g]?([^%g]+)[%g]?$");
@ -100,7 +101,7 @@ public class PreprocessorInclude implements ReadLine {
this.config = config;
this.defines = defines;
this.charset = charset;
this.reader2 = reader;
this.reader2 = new ReadLineQuoteComment(reader);
this.definitionsContainer = definitionsContainer;
this.filesUsedCurrent = filesUsedCurrent;
this.filesUsedGlobal = filesUsedGlobal;
@ -161,6 +162,11 @@ public class PreprocessorInclude implements ReadLine {
if (m3.find()) {
return manageDefinitionInclude(s, m3);
}
} else {
final Matcher2 m1 = includePatternStdlib.matcher(s);
if (m1.find()) {
return manageFileInclude(s, m1, false);
}
}
final Matcher2 mUrl = includeURLPattern.matcher(s);
if (s.getPreprocessorError() == null && mUrl.find()) {
@ -260,6 +266,10 @@ public class PreprocessorInclude implements ReadLine {
}
private InputStream getStdlibInputStream(String filename) {
return Stdlib.getResourceAsStream(filename);
}
private InputStream getStdlibInputStreamOld(String filename) {
if (filename.endsWith(".puml") == false) {
filename = filename + ".puml";
}

View File

@ -0,0 +1,84 @@
/* ========================================================================
* PlantUML : a free UML diagram generator
* ========================================================================
*
* (C) Copyright 2009-2017, Arnaud Roques
*
* Project Info: http://plantuml.com
*
* If you like this project or if you find it useful, you can support us at:
*
* http://plantuml.com/patreon (only 1$ per month!)
* http://plantuml.com/paypal
*
* This file is part of PlantUML.
*
* PlantUML is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* PlantUML distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
* License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*
*
* Original Author: Arnaud Roques
*
*
*/
package net.sourceforge.plantuml.preproc;
import java.io.IOException;
import net.sourceforge.plantuml.CharSequence2;
import net.sourceforge.plantuml.CharSequence2Impl;
public class ReadLineQuoteComment implements ReadLine {
private final ReadLine raw;
private boolean longComment = false;
public ReadLineQuoteComment(ReadLine source) {
this.raw = source;
}
public void close() throws IOException {
raw.close();
}
public CharSequence2 readLine() throws IOException {
while (true) {
final CharSequence2 result = raw.readLine();
if (result == null) {
return null;
}
final String trim = result.toString().replace('\t', ' ').trim();
if (this.longComment && trim.endsWith("'/")) {
this.longComment = false;
continue;
}
if (this.longComment) {
continue;
}
if (trim.startsWith("'")) {
continue;
}
if (trim.startsWith("/'") && trim.endsWith("'/")) {
continue;
}
if (trim.startsWith("/'") && trim.contains("'/") == false) {
this.longComment = true;
continue;
}
return ((CharSequence2Impl) result).removeInnerComment();
}
}
}

View File

@ -0,0 +1,203 @@
package net.sourceforge.plantuml.preproc;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.ref.SoftReference;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import net.sourceforge.plantuml.Log;
import org.brotli.dec.BrotliInputStream;
public class Stdlib {
static private final Map<String, Stdlib> all = new ConcurrentHashMap<String, Stdlib>();
static class Portion {
int position;
int length;
Portion(int position, int length) {
this.position = position;
this.length = length;
}
public byte[] of(DataInputStream is) throws IOException {
is.skipBytes(position);
final byte result[] = new byte[length];
is.readFully(result);
is.close();
return result;
}
}
private final Map<String, Portion> data = new HashMap<String, Portion>();
private final Map<String, SoftReference<byte[]>> cache = new ConcurrentHashMap<String, SoftReference<byte[]>>();
private final String name;
private final Map<String, String> info = new HashMap<String, String>();
public static InputStream getResourceAsStream(String fullname) {
fullname = fullname.toLowerCase().replace(".puml", "");
final int last = fullname.indexOf('/');
if (last == -1) {
return null;
}
try {
final Stdlib folder = retrieve(fullname.substring(0, last));
if (folder == null) {
return null;
}
final byte[] data = folder.getData(fullname.substring(last + 1));
if (data == null) {
return null;
}
return new ByteArrayInputStream(data);
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
private static InputStream getInternalInputStream(String fullname, String extension) {
final String res = "/stdlib/" + fullname + extension;
return Stdlib.class.getResourceAsStream(res);
}
private static Stdlib retrieve(final String name) throws IOException {
Stdlib result = all.get(name);
if (result == null) {
result = new Stdlib(name);
all.put(name, result);
}
return result;
}
private Stdlib(String name) throws IOException {
this.name = name;
Log.info("Opening archive " + name);
int pos = 0;
final DataInputStream is = getDataIndex();
fillMap(is.readUTF());
while (true) {
final String filename = is.readUTF();
if (filename.length() == 0) {
break;
}
final int len = is.readInt();
this.data.put(filename.toLowerCase(), new Portion(pos, len));
pos += len;
}
is.close();
}
private void fillMap(String infoString) {
for (String s : infoString.split("\n")) {
if (s.contains("=")) {
final String data[] = s.split("=");
this.info.put(data[0], data[1]);
}
}
}
private DataInputStream getDataIndex() {
final InputStream raw = getInternalInputStream(name, "-idx.repx");
if (raw == null) {
return null;
}
return new DataInputStream(raw);
}
private DataInputStream getFullTexts() throws IOException {
final InputStream raw = getInternalInputStream(name, "-dat.repx");
if (raw == null) {
return null;
}
return new DataInputStream(new BrotliInputStream(raw));
}
private byte[] getData(String filename) throws IOException {
final SoftReference<byte[]> ref = cache.get(filename);
byte[] result = ref == null ? null : ref.get();
final String full = name + "/" + filename + ".puml";
if (result == null) {
result = getDataSlow(filename);
cache.put(filename, new SoftReference<byte[]>(result));
Log.info("Reading " + full);
} else {
Log.info("Retrieving " + full);
}
return result;
}
private byte[] getDataSlow(String filename) throws IOException {
final Portion portion = data.get(filename);
return portion.of(getFullTexts());
}
public static void extractStdLib() throws IOException {
for (String name : getAll()) {
final Stdlib folder = new Stdlib(name);
folder.extractMeFull(new File("stdlib", name));
}
}
private static List<String> getAll() throws IOException {
final List<String> result = new ArrayList<String>();
final InputStream home = getInternalInputStream("home", ".repx");
final BufferedReader br = new BufferedReader(new InputStreamReader(home));
String name;
while ((name = br.readLine()) != null) {
result.add(name);
}
return Collections.unmodifiableList(result);
}
private void extractMeFull(File dir) throws IOException {
final DataInputStream idx = getDataIndex();
final DataInputStream txt = getFullTexts();
final String infoString = idx.readUTF();
while (true) {
final String filename = idx.readUTF();
if (filename.length() == 0) {
idx.close();
txt.close();
return;
}
final int len = idx.readInt();
final File f = new File("stdlib/" + name + "/" + filename + ".puml");
f.getParentFile().mkdirs();
final FileOutputStream fos = new FileOutputStream(f);
final byte data[] = new byte[len];
txt.readFully(data);
fos.write(data);
fos.close();
}
}
public static void addInfoVersion(List<String> strings) {
try {
for (String name : getAll()) {
final Stdlib folder = new Stdlib(name);
strings.add("* " + name + " (Version " + folder.getVersion() + ")");
}
} catch (IOException e) {
e.printStackTrace();
}
}
private String getVersion() {
return info.get("VERSION");
}
}

View File

@ -57,8 +57,8 @@ public class PSystemProjectFactory2 extends UmlDiagramFactory {
protected List<Command> createCommands() {
final List<Command> cmds = new ArrayList<Command>();
cmds.add(new CommandNope());
cmds.add(new CommandComment());
cmds.add(new CommandMultilinesComment());
// cmds.add(new CommandComment());
// cmds.add(new CommandMultilinesComment());
cmds.add(new CommandAffectation());
cmds.add(new CommandCloseWeekDay());
return cmds;

View File

@ -63,8 +63,8 @@ public class GanttDiagramFactory extends UmlDiagramFactory {
final List<Command> cmds = new ArrayList<Command>();
//addCommonCommands(cmds);
cmds.add(new CommandNope());
cmds.add(new CommandComment());
cmds.add(new CommandMultilinesComment());
// cmds.add(new CommandComment());
// cmds.add(new CommandMultilinesComment());
for (Command cmd : getLanguageCommands()) {
cmds.add(cmd);
}

View File

@ -48,12 +48,12 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import net.sourceforge.plantuml.AlignParam;
import net.sourceforge.plantuml.ColorParam;
import net.sourceforge.plantuml.Dimension2DDouble;
import net.sourceforge.plantuml.FontParam;
import net.sourceforge.plantuml.ISkinParam;
import net.sourceforge.plantuml.LineParam;
import net.sourceforge.plantuml.OptionFlags;
import net.sourceforge.plantuml.SkinParamUtils;
import net.sourceforge.plantuml.StringUtils;
import net.sourceforge.plantuml.UmlDiagramType;
@ -66,6 +66,7 @@ import net.sourceforge.plantuml.cucadiagram.Member;
import net.sourceforge.plantuml.cucadiagram.MethodsOrFieldsArea;
import net.sourceforge.plantuml.cucadiagram.Stereotype;
import net.sourceforge.plantuml.cucadiagram.dot.GraphvizVersion;
import net.sourceforge.plantuml.graphic.HorizontalAlignment;
import net.sourceforge.plantuml.graphic.HtmlColor;
import net.sourceforge.plantuml.graphic.HtmlColorTransparent;
import net.sourceforge.plantuml.graphic.StringBounder;
@ -74,6 +75,7 @@ import net.sourceforge.plantuml.graphic.TextBlockEmpty;
import net.sourceforge.plantuml.graphic.TextBlockWidth;
import net.sourceforge.plantuml.graphic.USymbol;
import net.sourceforge.plantuml.graphic.color.ColorType;
import net.sourceforge.plantuml.graphic.color.Colors;
import net.sourceforge.plantuml.posimo.Moveable;
import net.sourceforge.plantuml.skin.rose.Rose;
import net.sourceforge.plantuml.svek.image.EntityImageState;
@ -301,7 +303,10 @@ public class Cluster implements Moveable {
}
public void drawU(UGraphic ug, UStroke stroke, final UmlDiagramType umlDiagramType, final ISkinParam skinParam2) {
ug.draw(new UComment("cluster " + group.getCode().getFullName()));
final String fullName = group.getCode().getFullName();
if (fullName.startsWith("##") == false) {
ug.draw(new UComment("cluster " + fullName));
}
final Stereotype stereotype = group.getStereotype();
HtmlColor borderColor;
if (umlDiagramType == UmlDiagramType.STATE) {
@ -351,9 +356,11 @@ public class Cluster implements Moveable {
final double roundCorner = group.getUSymbol() == null ? 0 : group.getUSymbol().getSkinParameter()
.getRoundCorner(skinParam, stereotype);
final UStroke stroke2 = getStrokeInternal(skinParam2);
final ClusterDecoration decoration = new ClusterDecoration(style, group.getUSymbol(), ztitle, zstereo,
minX, minY, maxX, maxY, getStroke(skinParam2, group.getStereotype()));
decoration.drawU(ug, back, borderColor, skinParam2.shadowing(), roundCorner);
minX, minY, maxX, maxY, stroke2);
decoration.drawU(ug, back, borderColor, skinParam2.shadowing(), roundCorner,
skinParam2.getHorizontalAlignment(AlignParam.PACKAGE_TITLE_ALIGNMENT, null));
return;
}
final URectangle rect = new URectangle(maxX - minX, maxY - minY);
@ -372,10 +379,17 @@ public class Cluster implements Moveable {
}
private UStroke getStroke(ISkinParam skinParam, Stereotype stereo) {
UStroke stroke = skinParam.getThickness(LineParam.packageBorder, stereo);
private UStroke getStrokeInternal(ISkinParam skinParam) {
final Colors colors = group.getColors(skinParam);
if (colors.getSpecificLineStroke() != null) {
return colors.getSpecificLineStroke();
}
if (group.getUSymbol() != null) {
return group.getUSymbol().getSkinParameter().getStroke(skinParam, group.getStereotype());
}
UStroke stroke = skinParam.getThickness(LineParam.packageBorder, group.getStereotype());
if (stroke == null) {
stroke = new UStroke(2.0);
stroke = new UStroke(1.5);
}
return stroke;
}
@ -721,6 +735,9 @@ public class Cluster implements Moveable {
Line.appendTable(sblabel, getTitleAndAttributeWidth(), getTitleAndAttributeHeight() - 5, colorTitle);
sblabel.append(">");
label = sblabel.toString();
final HorizontalAlignment align = skinParam
.getHorizontalAlignment(AlignParam.PACKAGE_TITLE_ALIGNMENT, null);
sb.append("labeljust=\"" + align.getGraphVizValue() + "\";");
} else {
label = "\"\"";
}

View File

@ -36,6 +36,7 @@
*/
package net.sourceforge.plantuml.svek;
import net.sourceforge.plantuml.graphic.HorizontalAlignment;
import net.sourceforge.plantuml.graphic.HtmlColor;
import net.sourceforge.plantuml.graphic.SymbolContext;
import net.sourceforge.plantuml.graphic.TextBlock;
@ -85,15 +86,16 @@ public class ClusterDecoration {
public final static int marginTitleY1 = 3;
public final static int marginTitleY2 = 3;
public void drawU(UGraphic ug, HtmlColor backColor, HtmlColor borderColor, boolean shadowing, double roundCorner) {
public void drawU(UGraphic ug, HtmlColor backColor, HtmlColor borderColor, boolean shadowing, double roundCorner,
HorizontalAlignment titleAlignment) {
final SymbolContext biColor = new SymbolContext(backColor, borderColor);
if (symbol == null) {
throw new UnsupportedOperationException();
}
final SymbolContext symbolContext = biColor.withShadow(shadowing).withStroke(defaultStroke)
.withRoundCorner(roundCorner);
symbol.asBig(title, stereo, maxX - minX, maxY - minY, symbolContext)
.drawU(ug.apply(new UTranslate(minX, minY)));
symbol.asBig(title, titleAlignment, stereo, maxX - minX, maxY - minY, symbolContext).drawU(
ug.apply(new UTranslate(minX, minY)));
// return;
// }
// if (style == PackageStyle.NODE) {

View File

@ -60,6 +60,7 @@ import net.sourceforge.plantuml.graphic.TextBlockUtils;
import net.sourceforge.plantuml.graphic.USymbol;
import net.sourceforge.plantuml.graphic.USymbolFolder;
import net.sourceforge.plantuml.graphic.color.ColorType;
import net.sourceforge.plantuml.graphic.color.Colors;
import net.sourceforge.plantuml.svek.AbstractEntityImage;
import net.sourceforge.plantuml.svek.Margins;
import net.sourceforge.plantuml.svek.ShapeType;
@ -104,7 +105,8 @@ public class EntityImageDescription extends AbstractEntityImage {
this.url = entity.getUrl99();
HtmlColor backcolor = getEntity().getColors(getSkinParam()).getColor(ColorType.BACK);
final Colors colors = entity.getColors(skinParam);
HtmlColor backcolor = colors.getColor(ColorType.BACK);
if (backcolor == null) {
backcolor = SkinParamUtils.getColor(getSkinParam(), symbol.getColorParamBack(), getStereo());
}
@ -112,7 +114,8 @@ public class EntityImageDescription extends AbstractEntityImage {
assert getStereo() == stereotype;
final HtmlColor forecolor = SkinParamUtils.getColor(getSkinParam(), symbol.getColorParamBorder(), stereotype);
final double roundCorner = symbol.getSkinParameter().getRoundCorner(getSkinParam(), stereotype);
final UStroke stroke = symbol.getSkinParameter().getStroke(getSkinParam(), stereotype);
final UStroke stroke = colors.muteStroke(symbol.getSkinParameter().getStroke(getSkinParam(), stereotype));
final SymbolContext ctx = new SymbolContext(backcolor, forecolor).withStroke(stroke)
.withShadow(getSkinParam().shadowing2(symbol.getSkinParameter())).withRoundCorner(roundCorner);
@ -162,19 +165,25 @@ public class EntityImageDescription extends AbstractEntityImage {
@Override
public Margins getShield(StringBounder stringBounder) {
if (hideText && (useRankSame == false || hasSomeHorizontalLink((ILeaf) getEntity(), links) == false)) {
final Dimension2D dimStereo = stereo.calculateDimension(stringBounder);
final Dimension2D dimDesc = desc.calculateDimension(stringBounder);
final Dimension2D dimSmall = asSmall.calculateDimension(stringBounder);
final double x = Math.max(dimStereo.getWidth(), dimDesc.getWidth());
double suppX = x - dimSmall.getWidth();
if (suppX < 1) {
suppX = 1;
}
final double y = MathUtils.max(1, dimDesc.getHeight(), dimStereo.getHeight());
return new Margins(suppX / 2, suppX / 2, y, y);
if (hideText == false) {
return Margins.NONE;
}
return Margins.NONE;
if (useRankSame && hasSomeHorizontalLink((ILeaf) getEntity(), links)) {
return Margins.NONE;
}
if (hasSomeHorizontalLinkDoubleDecorated((ILeaf) getEntity(), links)) {
return Margins.NONE;
}
final Dimension2D dimStereo = stereo.calculateDimension(stringBounder);
final Dimension2D dimDesc = desc.calculateDimension(stringBounder);
final Dimension2D dimSmall = asSmall.calculateDimension(stringBounder);
final double x = Math.max(dimStereo.getWidth(), dimDesc.getWidth());
double suppX = x - dimSmall.getWidth();
if (suppX < 1) {
suppX = 1;
}
final double y = MathUtils.max(1, dimDesc.getHeight(), dimStereo.getHeight());
return new Margins(suppX / 2, suppX / 2, y, y);
}
private boolean hasSomeHorizontalLink(ILeaf leaf, Collection<Link> links) {
@ -186,6 +195,15 @@ public class EntityImageDescription extends AbstractEntityImage {
return false;
}
private boolean hasSomeHorizontalLinkDoubleDecorated(ILeaf leaf, Collection<Link> links) {
for (Link link : links) {
if (link.getLength() == 1 && link.contains(leaf) && link.getType().isDoubleDecorated()) {
return true;
}
}
return false;
}
final public void drawU(UGraphic ug) {
ug.draw(new UComment("entity " + getEntity().getCode().getFullName()));
if (url != null) {

View File

@ -37,6 +37,7 @@ package net.sourceforge.plantuml.svek.image;
import java.awt.geom.Dimension2D;
import net.sourceforge.plantuml.AlignParam;
import net.sourceforge.plantuml.ColorParam;
import net.sourceforge.plantuml.Dimension2DDouble;
import net.sourceforge.plantuml.FontParam;
@ -105,7 +106,7 @@ public class EntityImageEmptyPackage extends AbstractEntityImage {
private UStroke getStroke() {
UStroke stroke = getSkinParam().getThickness(LineParam.packageBorder, getStereo());
if (stroke == null) {
stroke = new UStroke(2.0);
stroke = new UStroke(1.5);
}
return stroke;
}
@ -128,7 +129,8 @@ public class EntityImageEmptyPackage extends AbstractEntityImage {
stereoBlock, 0, 0, widthTotal, heightTotal, getStroke());
decoration.drawU(ug, back, SkinParamUtils.getColor(getSkinParam(), ColorParam.packageBorder, getStereo()),
getSkinParam().shadowing(), roundCorner);
getSkinParam().shadowing(), roundCorner,
getSkinParam().getHorizontalAlignment(AlignParam.PACKAGE_TITLE_ALIGNMENT, null));
if (url != null) {
ug.closeAction();

View File

@ -296,43 +296,46 @@ public class SvgGraphics {
}
public void closeLink() {
if (pendingLink2.size() > 0) {
final Element element = pendingLink2.get(0);
pendingLink2.remove(0);
getG().appendChild(element);
if (pendingAction.size() > 0) {
final Element element = pendingAction.get(0);
pendingAction.remove(0);
if (element.getFirstChild() != null) {
// Empty link
getG().appendChild(element);
}
}
}
private final List<Element> pendingLink2 = new ArrayList<Element>();
private final List<Element> pendingAction = new ArrayList<Element>();
public void openLink(String url, String title, String target) {
if (url == null) {
throw new IllegalArgumentException();
}
if (pendingLink2.size() > 0) {
if (pendingAction.size() > 0) {
closeLink();
}
pendingLink2.add(0, (Element) document.createElement("a"));
pendingLink2.get(0).setAttribute("target", target);
pendingLink2.get(0).setAttribute("xlink:href", url);
pendingLink2.get(0).setAttribute("xlink:type", "simple");
pendingLink2.get(0).setAttribute("xlink:actuate", "onRequest");
pendingLink2.get(0).setAttribute("xlink:show", "new");
pendingAction.add(0, (Element) document.createElement("a"));
pendingAction.get(0).setAttribute("target", target);
pendingAction.get(0).setAttribute("xlink:href", url);
pendingAction.get(0).setAttribute("xlink:type", "simple");
pendingAction.get(0).setAttribute("xlink:actuate", "onRequest");
pendingAction.get(0).setAttribute("xlink:show", "new");
if (title == null) {
pendingLink2.get(0).setAttribute("xlink:title", url);
pendingAction.get(0).setAttribute("xlink:title", url);
} else {
title = title.replaceAll("\\\\n", "\n");
pendingLink2.get(0).setAttribute("xlink:title", title);
pendingAction.get(0).setAttribute("xlink:title", title);
}
}
public final Element getG() {
if (pendingLink2.size() == 0) {
if (pendingAction.size() == 0) {
return gRoot;
}
return pendingLink2.get(0);
return pendingAction.get(0);
}
public void svgRectangle(double x, double y, double width, double height, double rx, double ry, double deltaShadow,

View File

@ -394,12 +394,13 @@ public class ImageBuilder {
}
final UGraphicSvg ug;
if (mybackcolor instanceof HtmlColorGradient) {
ug = new UGraphicSvg(dim, colorMapper, (HtmlColorGradient) mybackcolor, false, scale, svgLinkTarget, hover, seed);
ug = new UGraphicSvg(dim, colorMapper, (HtmlColorGradient) mybackcolor, false, scale, svgLinkTarget, hover,
seed);
} else if (backColor == null || backColor.equals(Color.WHITE)) {
ug = new UGraphicSvg(dim, colorMapper, false, scale, svgLinkTarget, hover, seed);
} else {
ug = new UGraphicSvg(dim, colorMapper, StringUtils.getAsHtml(backColor), false, scale, svgLinkTarget, hover,
seed);
ug = new UGraphicSvg(dim, colorMapper, StringUtils.getAsHtml(backColor), false, scale, svgLinkTarget,
hover, seed);
}
return ug;

View File

@ -44,6 +44,7 @@ public class UText implements UShape {
private final String text;
private final FontConfiguration font;
private final String ariaLabel;
@Override
public String toString() {
@ -51,9 +52,18 @@ public class UText implements UShape {
}
public UText(String text, FontConfiguration font) {
this(text, font, null);
}
private UText(String text, FontConfiguration font, String ariaLabel) {
assert text.indexOf('\t') == -1;
this.text = text;
this.font = font;
this.ariaLabel = ariaLabel;
}
public UText withAriaLabel(String newAriaLabel) {
return new UText(text, font, newAriaLabel);
}
public String getText() {
@ -70,6 +80,10 @@ public class UText implements UShape {
return descent;
}
public String getAriaLabel() {
return ariaLabel;
}
}

View File

@ -199,7 +199,9 @@ public class UGraphicG2d extends AbstractUGraphic<Graphics2D> implements EnsureV
public void ensureVisible(double x, double y) {
for (Url u : urls) {
u.ensureVisible(x, y);
if (getClip() == null || getClip().isInside(x, y)) {
u.ensureVisible(x, y);
}
}
}

View File

@ -44,7 +44,11 @@ import java.util.List;
import net.sourceforge.plantuml.StringUtils;
import net.sourceforge.plantuml.code.AsciiEncoder;
import net.sourceforge.plantuml.code.AsciiEncoderFinalZeros;
import net.sourceforge.plantuml.code.CompressionZlib;
import net.sourceforge.plantuml.code.CompressionZopfliZlib;
import net.sourceforge.plantuml.code.PairInt;
import net.sourceforge.plantuml.code.SpiralOnRectangle;
import net.sourceforge.plantuml.ugraphic.ColorChangerMonochrome;
public enum SpriteGrayLevel {
@ -113,7 +117,6 @@ public enum SpriteGrayLevel {
// final int type = img.getType();
final List<String> result = new ArrayList<String>();
final AsciiEncoder encoder = new AsciiEncoder();
for (int y = 0; y < height; y += 2) {
final StringBuilder sb = new StringBuilder();
@ -123,7 +126,7 @@ public enum SpriteGrayLevel {
final int level2 = getGrayOn16(img, x, y + 1) / 2;
assert level2 >= 0 && level2 <= 7;
final int v = level1 * 8 + level2;
sb.append(encoder.encode6bit((byte) v));
sb.append(AsciiEncoder.encode6bit((byte) v));
}
result.add(sb.toString());
}
@ -136,7 +139,6 @@ public enum SpriteGrayLevel {
// final int type = img.getType();
final List<String> result = new ArrayList<String>();
final AsciiEncoder encoder = new AsciiEncoder();
for (int y = 0; y < height; y += 3) {
final StringBuilder sb = new StringBuilder();
@ -148,7 +150,7 @@ public enum SpriteGrayLevel {
final int level3 = getGrayOn16(img, x, y + 2) / 4;
assert level3 >= 0 && level3 <= 3;
final int v = level1 * 16 + level2 * 4 + level3;
sb.append(encoder.encode6bit((byte) v));
sb.append(AsciiEncoder.encode6bit((byte) v));
}
result.add(sb.toString());
}
@ -198,14 +200,13 @@ public enum SpriteGrayLevel {
}
private Sprite buildSprite8(int width, int height, List<CharSequence> strings) {
final AsciiEncoder encoder = new AsciiEncoder();
final SpriteMonochrome result = new SpriteMonochrome(width, height, 8);
for (int col = 0; col < result.getWidth(); col++) {
for (int line = 0; line < strings.size(); line++) {
if (col >= strings.get(line).length()) {
continue;
}
final int v = encoder.decode6bit(strings.get(line).charAt(col));
final int v = AsciiEncoder.decode6bit(strings.get(line).charAt(col));
final int w1 = v / 8;
final int w2 = v % 8;
result.setPixel(col, line * 2, w1);
@ -217,14 +218,13 @@ public enum SpriteGrayLevel {
}
private Sprite buildSprite4(int width, int height, List<CharSequence> strings) {
final AsciiEncoder encoder = new AsciiEncoder();
final SpriteMonochrome result = new SpriteMonochrome(width, height, 4);
for (int col = 0; col < result.getWidth(); col++) {
for (int line = 0; line < strings.size(); line++) {
if (col >= strings.get(line).length()) {
continue;
}
int v = encoder.decode6bit(strings.get(line).charAt(col));
int v = AsciiEncoder.decode6bit(strings.get(line).charAt(col));
final int w1 = v / 16;
v = v % 16;
final int w2 = v / 4;
@ -242,18 +242,33 @@ public enum SpriteGrayLevel {
final int width = img.getWidth();
final int height = img.getHeight();
final byte raw[] = new byte[width * height];
final BufferedImage grayImg = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
int cpt = 0;
final int coef = 16 / nbColor;
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
final int color = getGrayOn16(img, x, y) / coef;
raw[cpt++] = (byte) color;
grayImg.setRGB(x, y, color * coef);
}
}
final byte[] comp = new CompressionZlib().compress(raw);
return cut(new AsciiEncoder().encode(comp));
// final byte[] comp = new CompressionZlib().compress(raw);
final byte[] comp = new CompressionZopfliZlib().compress(raw);
return cut(new AsciiEncoderFinalZeros().encode(comp));
}
private List<String> encodeZSpiral(BufferedImage img) {
final int width = img.getWidth();
final int height = img.getHeight();
final byte raw[] = new byte[width * height];
final int coef = 16 / nbColor;
final SpiralOnRectangle spiral = new SpiralOnRectangle(width, height);
for (int cpt = 0; cpt < width * height; cpt++) {
final PairInt pt = spiral.nextPoint();
final int color = getGrayOn16(img, pt.getX(), pt.getY()) / coef;
raw[cpt] = (byte) color;
}
// final byte[] comp = new CompressionZlib().compress(raw);
final byte[] comp = new CompressionZopfliZlib().compress(raw);
return cut(new AsciiEncoderFinalZeros().encode(comp));
}
private List<String> cut(String s) {

View File

@ -460,6 +460,7 @@ public enum License {
text.add("Stdlib Icons provided https://github.com/tupadr3/plantuml-icon-font-sprites");
text.add("ASCIIMathML (c) Peter Jipsen http://www.chapman.edu/~jipsen");
text.add("ASCIIMathML (c) David Lippman http://www.pierce.ctc.edu/dlippman");
text.add("CafeUndZopfli ported by Eugene Klyuchnikov https://github.com/eustas/CafeUndZopfli");
text.add("");
return text;
}

View File

@ -62,8 +62,8 @@ import net.sourceforge.plantuml.core.ImageData;
import net.sourceforge.plantuml.cucadiagram.dot.GraphvizUtils;
import net.sourceforge.plantuml.graphic.GraphicPosition;
import net.sourceforge.plantuml.graphic.GraphicStrings;
import net.sourceforge.plantuml.preproc.Preprocessor;
import net.sourceforge.plantuml.preproc.PreprocessorInclude;
import net.sourceforge.plantuml.preproc.Stdlib;
import net.sourceforge.plantuml.svek.TextBlockBackcolored;
import net.sourceforge.plantuml.ugraphic.ColorMapperIdentity;
import net.sourceforge.plantuml.ugraphic.ImageBuilder;
@ -173,6 +173,9 @@ public class PSystemVersion extends AbstractPSystem {
strings.add("plantuml.include.path: " + PreprocessorInclude.getenv("plantuml.include.path"));
}
strings.add(" ");
strings.add("<b>Stdlib:");
Stdlib.addInfoVersion(strings);
strings.add(" ");
strings.addAll(GraphvizUtils.getTestDotStrings(true));
strings.add(" ");
@ -206,7 +209,8 @@ public class PSystemVersion extends AbstractPSystem {
add(strings, "<u>Original Eclipse Plugin</u>: Claude Durif & Anne Pecoil", withTag);
add(strings, "<u>Servlet & XWiki</u>: Maxime Sinclair", withTag);
add(strings, "<u>Docker</u>: David Ducatel", withTag);
add(strings, "<u>AWS lib</u>: milo-minderbinder", withTag);
add(strings, "<u>AWS lib</u>: Chris Passarello", withTag);
add(strings, "<u>Stdlib Icons</u>: tupadr3", withTag);
add(strings, "<u>Site design</u>: Raphael Cotisson", withTag);
add(strings, "<u>Logo</u>: Benjamin Croizet", withTag);

View File

@ -43,7 +43,7 @@ public class Version {
private static final int MAJOR_SEPARATOR = 1000000;
public static int version() {
return 1201719;
return 1201720;
}
public static int versionPatched() {
@ -88,7 +88,7 @@ public class Version {
}
public static long compileTime() {
return 1510487182424L;
return 1513011425649L;
}
public static String compileTimeString() {

View File

@ -1,155 +0,0 @@
/* ========================================================================
* PlantUML : a free UML diagram generator
* ========================================================================
*
* (C) Copyright 2009-2017, Arnaud Roques
*
* Project Info: http://plantuml.com
*
* If you like this project or if you find it useful, you can support us at:
*
* http://plantuml.com/patreon (only 1$ per month!)
* http://plantuml.com/paypal
*
* This file is part of PlantUML.
*
* PlantUML is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* PlantUML distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
* License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*
*
* Original Author: Arnaud Roques
*
*
*/
package net.sourceforge.plantuml.webp;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.text.Normalizer;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.regex.Pattern;
import net.sourceforge.plantuml.version.PSystemVersion;
public class Portraits {
private final static List<Portrait> all = new ArrayList<Portrait>();
private final static AtomicInteger current = new AtomicInteger();
private static InputStream getInputStream() {
return PSystemVersion.class.getResourceAsStream("out.png");
}
static {
final InputStream is = getInputStream();
if (is != null) {
try {
read(is);
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
private static void read(InputStream is) throws IOException {
final DataInputStream dis = new DataInputStream(is);
final int nb = dis.readShort();
final List<String> names = new ArrayList<String>();
final List<Integer> ages = new ArrayList<Integer>();
final List<String> quotes = new ArrayList<String>();
for (int i = 0; i < nb; i++) {
names.add(dis.readUTF());
ages.add((int) dis.readByte());
quotes.add(dis.readUTF());
}
for (int i = 0; i < nb; i++) {
final int len = dis.readShort();
final byte data[] = new byte[len];
dis.readFully(data);
all.add(new Portrait(names.get(i), ages.get(i), quotes.get(i), data));
}
Collections.shuffle(all);
}
public static Portrait getOne() {
if (all.size() == 0) {
return null;
}
final int nb = current.get() % all.size();
return all.get(nb);
}
public static void nextOne() {
current.getAndIncrement();
}
public static Portrait getOne(String line) {
Portrait candidat = null;
for (Portrait p : all) {
final int dist = similar(p.getName(), line);
if (dist <= 3) {
if (candidat != null && dist < similar(candidat.getName(), line)) {
continue;
}
candidat = p;
}
}
return candidat;
}
public static int similar(String s1, String s2) {
final int[] tab1 = countLetter(s1);
final int[] tab2 = countLetter(s2);
int result = 0;
for (int i = 0; i < tab1.length; i++) {
result += Math.abs(tab1[i] - tab2[i]);
}
return result;
}
private static String noAccent(String str) {
final String nfdNormalizedString = Normalizer.normalize(str, Normalizer.Form.NFD);
final Pattern pattern = Pattern.compile("\\p{InCombiningDiacriticalMarks}+");
return pattern.matcher(nfdNormalizedString).replaceAll("");
}
private static int[] countLetter(String s) {
s = noAccent(s).toLowerCase(Locale.US);
final int[] result = new int[26];
for (int i = 0; i < s.length(); i++) {
final char c = s.charAt(i);
if (c >= 'a' && c <= 'z') {
result[c - 'a']++;
}
}
return result;
}
static final List<Portrait> getAll() {
return all;
}
}

View File

@ -0,0 +1,159 @@
/*
Copyright 2014 Google Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
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.
Author: eustas.ru@gmail.com (Eugene Klyuchnikov)
*/
package net.sourceforge.plantuml.zopfli;
class BlockSplitter {
static int split(Cookie cookie, byte[] input, int from, int to) {
LzStore store = cookie.store1;
store.reset();
Deflate.greedy(cookie, null, input, from, to, store);
int nPoints = splitLz(cookie, store.litLens, store.dists, store.size);
int pos = from;
char[] dists = store.dists;
char[] litLens = store.litLens;
int[] points = cookie.splitPoints;
points[0] = pos;
for (int i = 0, j = 1; j <= nPoints; ++j) {
for (int pj = points[j]; i < pj; ++i) {
pos += (dists[i] == 0) ? 1 : litLens[i];
}
points[j] = pos;
}
return nPoints;
}
// TODO: May be use some kind of SORTED data-structure for splitPoints?
static int splitLz(Cookie cookie, char[] litLens, char[] dists, int llSize) {
int[] splitPoints = cookie.splitPoints;
int[] splitSize = cookie.splitSize;
splitPoints[0] = 0;
splitSize[0] = Deflate.calculateBlockSize(cookie, litLens, dists, 0, llSize);
splitPoints[1] = llSize;
splitSize[1] = -1;
int numBlocks = 1;
int maxBlocks = cookie.blockSplittingMax;
if (llSize < 10) {
return numBlocks;
}
int lStart = 0;
int lEnd = llSize;
int blockN = 0;
while (numBlocks < maxBlocks) {
int llPos = findMinimum(cookie, litLens, dists, lStart, lEnd);
int splitL = Deflate.calculateBlockSize(cookie, litLens, dists, lStart, llPos);
int splitR = Deflate.calculateBlockSize(cookie, litLens, dists, llPos, lEnd);
if (splitL + splitR > splitSize[blockN] || llPos == lStart + 1 || llPos == lEnd) {
splitSize[blockN] = -1;
} else {
splitSize[blockN] = splitL;
numBlocks++;
blockN++;
System.arraycopy(splitPoints, blockN, splitPoints, blockN + 1, numBlocks - blockN);
System.arraycopy(splitSize, blockN, splitSize, blockN + 1, numBlocks - blockN);
splitPoints[blockN] = llPos;
splitSize[blockN] = splitR;
}
int longest = 0;
boolean found = false;
for (int i = 0; i < numBlocks; i++) {
int start = splitPoints[i];
int end = splitPoints[i + 1];
if ((splitSize[i] != -1) && end - start > longest) {
lStart = start;
lEnd = end;
found = true;
longest = end - start;
blockN = i;
}
}
if (!found) {
break;
}
if (lEnd - lStart < 10) {
break;
}
}
return numBlocks;
}
private static int findMinimum(Cookie cookie, char[] litLens, char[] dists, int from, int to) {
int start = from + 1;
int end = to;
if (end - start < 1024) {
int best = Integer.MAX_VALUE;
int result = start;
for (int i = start; i < end; i++) {
int v = Deflate.calculateBlockSize(cookie, litLens, dists, from, i)
+ Deflate.calculateBlockSize(cookie, litLens, dists, i, to);
if (v < best) {
best = v;
result = i;
}
}
return result;
} else {
int n = Cookie.SPLIT_PARTITIONS;
int[] p = cookie.p;
int[] vp = cookie.vp;
int lastBest = Integer.MAX_VALUE;
int pos = start;
while (true) {
if (end - start <= n) {
break;
}
for (int i = 0; i < n; i++) {
p[i] = start + (i + 1) * ((end - start) / (n + 1));
vp[i] = Deflate.calculateBlockSize(cookie, litLens, dists, from, p[i])
+ Deflate.calculateBlockSize(cookie, litLens, dists, p[i], to);
}
int bestI = 0;
int best = vp[0];
for (int i = 1; i < n; i++) {
if (vp[i] < best) {
best = vp[i];
bestI = i;
}
}
if (best > lastBest) {
break;
}
start = bestI == 0 ? start : p[bestI - 1];
end = bestI == n - 1 ? end : p[bestI + 1];
pos = p[bestI];
lastBest = best;
}
return pos;
}
}
}

View File

@ -0,0 +1,75 @@
/*
Copyright 2014 Google Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
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.
Author: eustas.ru@gmail.com (Eugene Klyuchnikov)
*/
package net.sourceforge.plantuml.zopfli;
public class Buffer {
byte[] data;
int size;
private int bp;
Buffer() {
data = new byte[65536];
}
public byte[] getData() {
return data;
}
public byte[] getResult() {
byte[] copy = new byte[size];
System.arraycopy(data,0,copy,0,size);
return copy;
}
public int getSize() {
return size;
}
void append(byte value) {
if (size == data.length) {
byte[] copy = new byte[size * 2];
System.arraycopy(data, 0, copy, 0, size);
data = copy;
}
data[size++] = value;
}
void addBits(int symbol, int length) {
for (int i = 0; i < length; i++) {
if (bp == 0) {
append((byte) 0);
}
int bit = (symbol >> i) & 1;
data[size - 1] |= bit << bp;
bp = (bp + 1) & 7;
}
}
void addHuffmanBits(int symbol, int length) {
for (int i = 0; i < length; i++) {
if (bp == 0) {
append((byte) 0);
}
int bit = (symbol >> (length - i - 1)) & 1;
data[size - 1] |= bit << bp;
bp = (bp + 1) & 7;
}
}
}

View File

@ -0,0 +1,191 @@
/*
Copyright 2014 Google Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
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.
Author: eustas.ru@gmail.com (Eugene Klyuchnikov)
*/
package net.sourceforge.plantuml.zopfli;
class Cookie {
static class Node {
int weight;
Node tail;
int count;
}
static final int SPLIT_PARTITIONS = 9;
private static final int POOL_MAX = 10240;
final static int[] intZeroes = new int[65536];
final static char[] charZeroes = new char[65536];
final static byte[] byteZeroes = new byte[65536];
final static int[] intMOnes = new int[65536];
final static char[] charOnes = new char[65536];
final static long[] costMax = new long[65536];
static {
for (int i = 0; i < 64; ++i) {
intMOnes[i] = -1;
charOnes[i] = 1;
costMax[i] = Long.MAX_VALUE;
}
expand(intMOnes);
expand(charOnes);
expand(costMax);
}
static void expand(Object array) {
for (int i = 64; i < 65536; i = i + i) {
System.arraycopy(array, 0, array, i, i);
}
}
final Node[] list0 = new Node[15];
final Node[] list1 = new Node[15];
final Node[] leaves1 = new Node[288];
final Node[] leaves2 = new Node[288];
private final Node[] nodes = new Node[POOL_MAX];
private int nextNode;
//final Node[] leaves2 = new Node[288];
/*private final static Comparator<Node> wc = new Comparator<Node>() {
@Override
public int compare(Node node, Node node2) {
int r = node.weight - node2.weight;
return r == 0 ? node.count - node2.count : r;
}
};*/
final int[] i320a = new int[320];
final int[] i320b = new int[320];
final int[] i320c = new int[320];
final int[] i288a = new int[288];
final int[] i288b = new int[288];
final int[] i288c = new int[288];
final int[] i289a = new int[289];
final char[] c259a = new char[259];
final int[] i32a = new int[32];
final int[] i32b = new int[32];
final int[] i32c = new int[32];
final int[] i19a = new int[19];
final int[] i19b = new int[19];
final int[] i19c = new int[19];
final int[] i16a = new int[16];
final int[] i16b = new int[16];
final int[] p = new int[SPLIT_PARTITIONS];
final int[] vp = new int[SPLIT_PARTITIONS];
final char[] lengthArray; // unsigned short, but really values are 0..258 == MAX_MATCH
final long[] costs;
final char[] path;
final int[] splitPoints;
final int[] splitSize;
final SymbolStats stats = new SymbolStats();
final SymbolStats bestStats = new SymbolStats();
final SymbolStats lastStats = new SymbolStats();
final Hash h = new Hash();
int lenVal;
int distVal;
int rnd = 42;
final LzStore store1;
final LzStore store2;
final LongestMatchCache lmc;
final int masterBlockSize;
final Node node(int weight, int count, Node tail) {
Node result = nodes[nextNode++];
result.weight = weight;
result.count = count;
result.tail = tail;
return result;
}
final void resetPool() {
nextNode = 0;
}
static void fill0(int[] array, int length) {
int i = 0;
while (i < length) {
int j = i + 65536;
if (j > length) {
j = length;
}
System.arraycopy(intZeroes, 0, array, i, j - i);
i = j;
}
}
static void fill0(char[] array, int length) {
int i = 0;
while (i < length) {
int j = i + 65536;
if (j > length) {
j = length;
}
System.arraycopy(charZeroes, 0, array, i, j - i);
i = j;
}
}
static void fillCostMax(long[] array, int length) {
int i = 0;
while (i < length) {
int j = i + 65536;
if (j > length) {
j = length;
}
System.arraycopy(costMax, 0, array, i, j - i);
i = j;
}
}
/**
* Maximum amount of blocks to split into.
* <p/>
* {@code 0} for unlimited.
*/
final int blockSplittingMax = 15;
Cookie(int masterBlockSize) { // TODO: + maxBlockSize?
this.masterBlockSize = masterBlockSize;
for (int i = 0; i < POOL_MAX; i++) {
nodes[i] = new Node();
}
splitPoints = new int[blockSplittingMax + 1];
splitSize = new int[blockSplittingMax + 1];
lengthArray = new char[masterBlockSize + 1]; // 2
costs = new long[masterBlockSize + 1]; // 8
path = new char[masterBlockSize + 1]; // 2
lmc = new LongestMatchCache(masterBlockSize); // 28
store1 = new LzStore(masterBlockSize); // 4
store2 = new LzStore(masterBlockSize); // 4
// 2 + 8 + 2 + 28 + 4 + 4 = 48
}
}

View File

@ -0,0 +1,796 @@
/*
Copyright 2014 Google Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
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.
Author: eustas.ru@gmail.com (Eugene Klyuchnikov)
*/
package net.sourceforge.plantuml.zopfli;
class Deflate {
static enum BlockType {
DYNAMIC,
FIXED
}
// final static int WINDOW_SIZE = 0x8000;
// final static int WINDOW_MASK = 0x7FFF;
// final static int MAX_MATCH = 258;
// final static int MIN_MATCH = 3;
// final static int MAX_CHAIN_HITS = 8192; // Should be less than WINDOW_SIZE
private static void getFixedTree(int[] llLengths, int[] dLengths) {
for (int i = 0; i < 144; i++) {
llLengths[i] = 8;
}
for (int i = 144; i < 256; i++) {
llLengths[i] = 9;
}
for (int i = 256; i < 280; i++) {
llLengths[i] = 7;
}
for (int i = 280; i < 288; i++) {
llLengths[i] = 8;
}
for (int i = 0; i < 32; i++) {
dLengths[i] = 5;
}
}
public static void greedy(Cookie cookie, LongestMatchCache lmc, byte[] input, int from, int to, LzStore store) {
Hash h = cookie.h;
h.init(input, Math.max(from - 0x8000, 0), from, to);
int prevLength = 0;
int prevMatch = 0;
char[] dummySubLen = cookie.c259a;
boolean matchAvailable = false;
for (int i = from; i < to; i++) {
h.updateHash(input, i, to);
findLongestMatch(cookie, lmc, from, h, input, i, to, 258, dummySubLen);
int len = cookie.lenVal;
int dist = cookie.distVal;
int lengthScore = dist > 1024 ? len - 1 : len;
int prevLengthScore = prevMatch > 1024 ? prevLength - 1 : prevLength;
if (matchAvailable) {
matchAvailable = false;
if (lengthScore > prevLengthScore + 1) {
store.append((char) (input[i - 1] & 0xFF), (char) 0);
if (lengthScore >= 3 && len < 258) {
matchAvailable = true;
prevLength = len;
prevMatch = dist;
continue;
}
} else {
store.append((char) prevLength, (char) prevMatch);
for (int j = 2; j < prevLength; j++) {
i++;
h.updateHash(input, i, to);
}
continue;
}
} else if (lengthScore >= 3 && len < 258) {
matchAvailable = true;
prevLength = len;
prevMatch = dist;
continue;
}
if (lengthScore >= 3) {
store.append((char) len, (char) dist);
} else {
len = 1;
store.append((char) (input[i] & 0xFF), (char) 0);
}
for (int j = 1; j < len; j++) {
i++;
h.updateHash(input, i, to);
}
}
}
static void findLongestMatch(Cookie cookie, LongestMatchCache lmc, int blockStart, Hash h, byte[] array,
int pos, int size, int limit, char[] subLen) {
//# WINDOW_SIZE = 0x8000
//# WINDOW_MASK = 0x7FFF
//# MIN_MATCH = 3
//# MAX_MATCH = 258
int offset = pos - blockStart;
char[] lmcLength = lmc != null ? lmc.length : null;
if (lmc != null && ((lmcLength[offset] == 0 || lmc.dist[offset] != 0))
&& (limit == 258 || lmcLength[offset] <= limit
|| subLen != null && lmc.maxCachedSubLen(offset) >= limit)) {
if (subLen == null || lmcLength[offset] <= lmc.maxCachedSubLen(offset)) {
cookie.lenVal = lmcLength[offset];
if (cookie.lenVal > limit) {
cookie.lenVal = limit;
}
if (subLen != null) {
lmc.cacheToSubLen(offset, cookie.lenVal, subLen);
cookie.distVal = subLen[cookie.lenVal];
} else {
cookie.distVal = lmc.dist[offset];
}
return;
}
limit = lmcLength[offset];
}
if (size - pos < 3) {
cookie.lenVal = 0;
cookie.distVal = 0;
return;
}
if (pos + limit > size) {
limit = size - pos;
}
int bestDist = 0;
int bestLength = 1;
int arrayEnd = pos + limit;
int chainCounter = 8192;
int[] hPrev = h.prev;
int[] hPrev2 = h.prev2;
int pp = h.head[h.val];
int threshold = h.same[pp];
int[] hashVal2 = h.hashVal2;
int marker = hashVal2[pp];
int p = hPrev[pp];
pp -= p;
int dist = pp > 0 ? pp : pp + 0x8000;
while (dist < 0x8000 && chainCounter > 0) {
int scan = pos;
int match = pos - dist;
if (array[scan + bestLength] == array[match + bestLength]) {
int same0 = h.same[pos & 0x7FFF];
if (same0 > 2 && array[scan] == array[match]) {
int same1 = h.same[match & 0x7FFF];
int same = same0 < same1 ? same0 : same1;
if (same > limit) {
same = limit;
}
scan += same;
match += same;
}
while (scan != arrayEnd && array[scan] == array[match]) {
scan++;
match++;
}
scan -= pos;
if (scan > bestLength) {
if (subLen != null) {
for (int j = bestLength + 1; j <= scan; j++) {
subLen[j] = (char) dist;
}
}
bestDist = dist;
bestLength = scan;
if (scan >= limit) {
break;
}
}
}
if (hPrev != hPrev2 && bestLength >= threshold && marker == hashVal2[p]) {
hPrev = hPrev2;
}
pp = p;
p = hPrev[p];
if (p == pp) {
break;
}
pp -= p;
dist += pp > 0 ? pp : 0x8000 + pp;
--chainCounter;
}
if (lmc != null && limit == 258 && subLen != null && lmcLength[offset] != 0 && lmc.dist[offset] == 0) {
if (bestLength < 3) {
lmc.dist[offset] = 0;
lmcLength[offset] = 0;
} else {
lmc.dist[offset] = (char)bestDist;
lmcLength[offset] = (char)bestLength;
}
lmc.subLenToCache(subLen, offset, bestLength);
}
cookie.distVal = bestDist;
cookie.lenVal = bestLength;
}
private static void deflatePart(Cookie cookie, Options options, byte[] input, int from, int to, boolean flush,
Buffer output) {
// assert from != to
switch (options.blockSplitting) {
case FIRST:
deflateSplittingFirst(cookie, options, flush, input, from, to, output);
break;
case LAST:
deflateSplittingLast(cookie, options, flush, input, from, to, output);
break;
case NONE:
deflateDynamicBlock(cookie, options, flush, input, from, to, output);
break;
}
}
private static void deflateDynamicBlock(Cookie cookie, Options options, boolean flush, byte[] input,
int from, int to, Buffer output) {
// assert from != to
LongestMatchCache lmc = cookie.lmc;
lmc.init(to - from);
BlockType type = BlockType.DYNAMIC;
LzStore store = Squeeze.optimal(cookie, options.numIterations, lmc, input, from, to);
if (store.size < 1000) {
LzStore fixedStore = cookie.store1;
fixedStore.reset();
Squeeze.bestFixedLengths(cookie, lmc, input, from, to, cookie.lengthArray, cookie.costs);
Squeeze.optimalRun(cookie, lmc, input, from, to, cookie.lengthArray, fixedStore);
int dynCost = calculateBlockSize(cookie, store.litLens, store.dists, 0, store.size);
int fixedCost = calculateFixedBlockSize(cookie, fixedStore.litLens,
fixedStore.dists, fixedStore.size);
if (fixedCost < dynCost) {
type = BlockType.FIXED;
store = fixedStore;
}
}
addLzBlock(cookie, type, flush, store.litLens, store.dists, 0, store.size, output);
}
private static void deflateSplittingLast(Cookie cookie, Options options, boolean flush,
byte[] input, int from, int to, Buffer output) {
// assert from != to
LongestMatchCache lmc = cookie.lmc;
lmc.init(to - from);
LzStore store = Squeeze.optimal(cookie, options.numIterations, lmc, input, from, to);
int nPoints = BlockSplitter.splitLz(cookie, store.litLens, store.dists, store.size);
int[] splitPoints = cookie.splitPoints;
for (int i = 1; i <= nPoints; i++) {
int start = splitPoints[i - 1];
int end = splitPoints[i];
addLzBlock(cookie, BlockType.DYNAMIC, i == nPoints && flush, store.litLens, store.dists, start, end, output);
}
}
private static void deflateSplittingFirst(Cookie cookie, Options options, boolean flush,
byte[] input, int from, int to, Buffer output) {
// assert from != to
int nPoints = BlockSplitter.split(cookie, input, from, to);
int[] splitPoints = cookie.splitPoints;
for (int i = 1; i <= nPoints; ++i) {
deflateDynamicBlock(cookie, options, i == nPoints && flush, input, splitPoints[i - 1], splitPoints[i], output);
}
}
static int calculateBlockSize(Cookie cookie, char[] litLens, char[] dists, int lStart, int lEnd) {
int[] llLengths = cookie.i288a;
System.arraycopy(Cookie.intZeroes, 0, llLengths, 0, 288);
int[] dLengths = cookie.i32a;
System.arraycopy(Cookie.intZeroes, 0, dLengths, 0, 32);
int result = 3;
int[] llCounts = cookie.i288b;
System.arraycopy(Cookie.intZeroes, 0, llCounts, 0, 288);
int[] dCounts = cookie.i32b;
System.arraycopy(Cookie.intZeroes, 0, dCounts, 0, 32);
int[] lengthSymbol = Util.LENGTH_SYMBOL;
int[] cachedDistSymbol = Util.CACHED_DIST_SYMBOL;
int[] lengthExtraBits = Util.LENGTH_EXTRA_BITS;
for (int i = lStart; i < lEnd; i++) {
int d = dists[i];
int l = litLens[i];
if (d == 0) {
llCounts[l]++;
} else {
llCounts[lengthSymbol[l]]++;
int distSymbol = cachedDistSymbol[d];
dCounts[distSymbol]++;
result += lengthExtraBits[l];
if (distSymbol > 3) {
result += (distSymbol / 2) - 1;
}
}
}
llCounts[256] = 1;
int[] llCountsCopy = cookie.i288c;
System.arraycopy(llCounts, 0, llCountsCopy, 0, 288);
optimizeHuffmanForRle(cookie, llCountsCopy);
Katajainen.lengthLimitedCodeLengths(cookie, llCountsCopy, 15, llLengths);
int[] dCountsCopy = cookie.i32c;
System.arraycopy(dCounts, 0, dCountsCopy, 0, 32);
optimizeHuffmanForRle(cookie, dCountsCopy);
Katajainen.lengthLimitedCodeLengths(cookie, dCountsCopy, 15, dLengths);
patchDistanceCodesForBuggyDecoders(dLengths);
result += simulateAddDynamicTree(cookie, llLengths, dLengths);
for (int i = 0; i < 288; ++i) {
result += llCounts[i] * llLengths[i];
}
for (int i = 0; i < 32; ++i) {
result += dCounts[i] * dLengths[i];
}
return result;
}
private static int calculateFixedBlockSize(Cookie cookie, char[] litLens, char[] dists, int size) {
int[] llLengths = cookie.i288a;
int[] dLengths = cookie.i32a;
getFixedTree(llLengths, dLengths);
int result = 3;
int[] cachedDistExtraBits = Util.CACHED_DIST_EXTRA_BITS;
int[] lengthExtraBits = Util.LENGTH_EXTRA_BITS;
int[] lengthSymbol = Util.LENGTH_SYMBOL;
for (int i = 0; i < size; i++) {
int d = dists[i];
int l = litLens[i];
if (d == 0) {
result += llLengths[l];
} else {
result += llLengths[lengthSymbol[l]];
result += lengthExtraBits[l];
result += 5;
result += d < 4097 ? cachedDistExtraBits[d] : d < 16385 ? d < 8193 ? 11 : 12 : 13;
}
}
result += llLengths[256];
return result;
}
private static void lzCounts(char[] litLens, char[] dists, int start, int end, int[] llCount, int[] dCount) {
int[] lengthSymbol = Util.LENGTH_SYMBOL;
int[] cachedDistSymbol = Util.CACHED_DIST_SYMBOL;
for (int i = start; i < end; i++) {
int d = dists[i];
int l = litLens[i];
if (d == 0) {
llCount[l]++;
} else {
llCount[lengthSymbol[l]]++;
dCount[cachedDistSymbol[d]]++;
}
}
llCount[256] = 1;
}
static void compress(Cookie cookie, Options options, byte[] input, Buffer output) {
int i = 0;
while (i < input.length) {
int j = Math.min(i + cookie.masterBlockSize, input.length);
deflatePart(cookie, options, input, i, j, j == input.length, output);
i = j;
}
}
private static void patchDistanceCodesForBuggyDecoders(int[] dLengths) {
int numDistCodes = 0;
for (int i = 0; i < 30; i++) {
if (dLengths[i] != 0) {
numDistCodes++;
if (numDistCodes == 2) {
return;
}
}
}
if (numDistCodes == 0) {
dLengths[0] = 1;
dLengths[1] = 1;
} else if (numDistCodes == 1) {
dLengths[dLengths[0] != 0 ? 1 : 0] = 1;
}
}
private static void addDynamicTree(Cookie cookie, int[] llLengths, int[] dLengths, Buffer output) {
int best = 0;
int bestSize = Integer.MAX_VALUE;
for(int i = 0; i < 8; i++) {
int size = simulateEncodeTree(cookie, llLengths, dLengths, (i & 1) != 0, (i & 2) != 0, (i & 4) != 0);
if (size < bestSize) {
bestSize = size;
best = i;
}
}
encodeTree(cookie, llLengths, dLengths, (best & 1) != 0, (best & 2) != 0, (best & 4) != 0, output);
}
private static void encodeTree(Cookie cookie, int[] llLengths, int[] dLengths,
boolean use16, boolean use17, boolean use18, Buffer output) {
int hLit = 29;
int hDist = 29;
while (hLit > 0 && llLengths[256 + hLit] == 0) {
hLit--;
}
while (hDist > 0 && dLengths[hDist] == 0) {
hDist--;
}
int lldTotal = hLit + 258 + hDist;
int[] lldLengths = cookie.i320b;
System.arraycopy(llLengths, 0, lldLengths, 0, 257 + hLit);
System.arraycopy(dLengths, 0, lldLengths, 257 + hLit, hDist + 1);
int rleSize = 0;
int[] rle = cookie.i320a;
int[] rleBits = cookie.i320c;
for (int i = 0; i < lldTotal; i++) {
int count = 1;
int symbol = lldLengths[i];
if (use16 || (symbol == 0 && (use17 || use18))) {
for (int j = i + 1; j < lldTotal && symbol == lldLengths[j]; j++) {
count++;
}
}
i += count - 1;
if (symbol == 0 && count > 2) {
if (use18) {
while (count > 10) {
int delta = count > 138 ? 138 : count;
rle[rleSize] = 18;
rleBits[rleSize++] = delta - 11;
count -= delta;
}
}
if (use17) {
while (count > 2) {
int delta = count > 10 ? 10 : count;
rle[rleSize] = 17;
rleBits[rleSize++] = delta - 3;
count -= delta;
}
}
}
if (use16 && count > 3) {
count--;
rle[rleSize] = symbol;
rleBits[rleSize++] = 0;
while (count > 2) {
int delta = count > 6 ? 6 : count;
rle[rleSize] = 16;
rleBits[rleSize++] = delta - 3;
count -= delta;
}
}
while (count != 0) {
rle[rleSize] = symbol;
rleBits[rleSize++] = 0;
count--;
}
}
int[] clCounts = cookie.i19a;
System.arraycopy(Cookie.intZeroes, 0, clCounts, 0, 19);
for (int i = 0; i < rleSize; ++i) {
clCounts[rle[i]]++;
}
int[] clCl = cookie.i19b;
System.arraycopy(Cookie.intZeroes, 0, clCl, 0, 19);
Katajainen.lengthLimitedCodeLengths(cookie, clCounts, 7, clCl);
int[] clSymbols = cookie.i19c;
lengthsToSymbols(clCl, 19, 7, clSymbols, cookie.i16a, cookie.i16b);
int[] order = Util.ORDER;
int hcLen = 15;
while (hcLen > 0 && clCounts[order[hcLen + 3]] == 0) {
hcLen--;
}
output.addBits(hLit, 5);
output.addBits(hDist, 5);
output.addBits(hcLen, 4);
for (int i = 0; i < hcLen + 4; i++) {
output.addBits(clCl[order[i]], 3);
}
for (int i = 0; i < rleSize; i++) {
int symbol = clSymbols[rle[i]];
output.addHuffmanBits(symbol, clCl[rle[i]]);
if (rle[i] == 16) {
output.addBits(rleBits[i], 2);
} else if (rle[i] == 17) {
output.addBits(rleBits[i], 3);
} else if (rle[i] == 18) {
output.addBits(rleBits[i], 7);
}
}
}
private static int simulateAddDynamicTree(Cookie cookie, int[] llLengths, int[] dLengths) {
int bestSize = Integer.MAX_VALUE;
for(int i = 0; i < 8; i++) {
int size = simulateEncodeTree(cookie, llLengths, dLengths, (i & 1) != 0, (i & 2) != 0, (i & 4) != 0);
if (size < bestSize) {
bestSize = size;
}
}
return bestSize;
}
// TODO: GetRid of RLE
private static int simulateEncodeTree(Cookie cookie, int[] llLengths, int[] dLengths,
boolean use16, boolean use17, boolean use18) {
int hLit = 29;
int hDist = 29;
while (hLit > 0 && llLengths[256 + hLit] == 0) {
hLit--;
}
while (hDist > 0 && dLengths[hDist] == 0) {
hDist--;
}
int lldTotal = hLit + 258 + hDist;
int[] lldLengths = cookie.i320b;
System.arraycopy(llLengths, 0, lldLengths, 0, 257 + hLit);
System.arraycopy(dLengths, 0, lldLengths, 257 + hLit, hDist + 1);
int[] rle = cookie.i320a;
int rleSize = 0;
for (int i = 0; i < lldTotal; i++) {
int count = 1;
int symbol = lldLengths[i];
if (use16 || (symbol == 0 && (use17 || use18))) {
for (int j = i + 1; j < lldTotal && symbol == lldLengths[j]; j++) {
count++;
}
}
i += count - 1;
if (symbol == 0 && count > 2) {
if (use18) {
while (count > 10) {
rle[rleSize++] = 18;
count -= count > 138 ? 138 : count;
}
}
if (use17) {
while (count > 2) {
rle[rleSize++] = 17;
count -= count > 10 ? 10 : count;
}
}
}
if (use16 && count > 3) {
count--;
rle[rleSize++] = symbol;
while (count > 2) {
rle[rleSize++] = 16;
count -= count > 6 ? 6 : count;
}
}
while (count != 0) {
rle[rleSize++] = symbol;
count--;
}
}
int[] clCounts = cookie.i19a;
System.arraycopy(Cookie.intZeroes, 0, clCounts, 0, 19);
for (int i = 0; i < rleSize; ++i) {
clCounts[rle[i]]++;
}
int[] clCl = cookie.i19b;
System.arraycopy(Cookie.intZeroes, 0, clCl, 0, 19);
Katajainen.lengthLimitedCodeLengths(cookie, clCounts, 7, clCl);
clCl[16] += 2;
clCl[17] += 3;
clCl[18] += 7;
int[] order = Util.ORDER;
int hcLen = 15;
while (hcLen > 0 && clCounts[order[hcLen + 3]] == 0) {
hcLen--;
}
int result = 5 + 5 + 4 + (hcLen + 4) * 3;
for (int i = 0; i < 19; i++) {
result += clCl[i] * clCounts[i];
}
return result;
}
private static void addLzBlock(Cookie cookie, BlockType type, boolean last, char[] litLens, char[] dists,
int lStart, int lEnd, Buffer output) {
int[] llLengths = cookie.i288a;
System.arraycopy(Cookie.intZeroes, 0, llLengths, 0, 288);
int[] dLengths = cookie.i32a;
System.arraycopy(Cookie.intZeroes, 0, dLengths, 0, 32);
int[] llCounts = cookie.i288b;
System.arraycopy(Cookie.intZeroes, 0, llCounts, 0, 288);
int[] dCounts = cookie.i32b;
System.arraycopy(Cookie.intZeroes, 0, dCounts, 0, 32);
output.addHuffmanBits(last ? 1 : 0, 1);
if (type == BlockType.FIXED) {
output.addHuffmanBits(2, 2); // 1, 0
} else { // DYNAMIC
output.addHuffmanBits(1, 2); // 0, 1
}
if (type == BlockType.FIXED) {
getFixedTree(llLengths, dLengths);
} else { // DYNAMIC
lzCounts(litLens, dists, lStart, lEnd, llCounts, dCounts);
optimizeHuffmanForRle(cookie, llCounts);
Katajainen.lengthLimitedCodeLengths(cookie, llCounts, 15, llLengths);
optimizeHuffmanForRle(cookie, dCounts);
Katajainen.lengthLimitedCodeLengths(cookie, dCounts, 15, dLengths);
patchDistanceCodesForBuggyDecoders(dLengths);
addDynamicTree(cookie, llLengths, dLengths, output);
}
int[] llSymbols = cookie.i288c;
System.arraycopy(Cookie.intZeroes, 0, llSymbols, 0, 288);
lengthsToSymbols(llLengths, 288, 15, llSymbols, cookie.i16a, cookie.i16b);
int[] dSymbols = cookie.i32b;
System.arraycopy(Cookie.intZeroes, 0, dSymbols, 0, 32);
lengthsToSymbols(dLengths, 32, 15, dSymbols, cookie.i16a, cookie.i16b);
addLzData(litLens, dists, lStart, lEnd, llSymbols, llLengths, dSymbols, dLengths, output);
output.addHuffmanBits(llSymbols[256], llLengths[256]);
}
private static void addLzData(char[] litLens, char[] dists, int lStart, int lEnd,
int[] llSymbols, int[] llLengths, int[] dSymbols, int[] dLengths, Buffer output) {
int[] cachedDistExtraBits = Util.CACHED_DIST_EXTRA_BITS;
int[] lengthExtraBits = Util.LENGTH_EXTRA_BITS;
int[] lengthExtraBitsValue = Util.LENGTH_EXTRA_BITS_VALUE;
int[] lengthSymbol = Util.LENGTH_SYMBOL;
int[] cachedDistSymbol = Util.CACHED_DIST_SYMBOL;
for (int i = lStart; i < lEnd; i++) {
int dist = dists[i];
int litLen = litLens[i];
if (dist == 0) {
output.addHuffmanBits(llSymbols[litLen], llLengths[litLen]);
} else {
int lls = lengthSymbol[litLen];
int ds = cachedDistSymbol[dist];
output.addHuffmanBits(llSymbols[lls], llLengths[lls]);
output.addBits(lengthExtraBitsValue[litLen], lengthExtraBits[litLen]);
output.addHuffmanBits(dSymbols[ds], dLengths[ds]);
output.addBits(Util.distExtraBitsValue(dist),
dist < 4097 ? cachedDistExtraBits[dist] : dist < 16385 ? dist < 8193 ? 11 : 12 : 13);
}
}
}
private static void lengthsToSymbols(int[] lengths, int n, int maxBits, int[] symbols, int[] blCount, int[] nextCode) {
System.arraycopy(Cookie.intZeroes, 0, blCount, 0, maxBits + 1);
System.arraycopy(Cookie.intZeroes, 0, nextCode, 0, maxBits + 1);
for (int i = 0; i < n; ++i) {
blCount[lengths[i]]++;
}
int code = 0;
blCount[0] = 0;
for (int bits = 1; bits <= maxBits; bits++) {
code = (code + blCount[bits - 1]) << 1;
nextCode[bits] = code;
}
for (int i = 0; i < n; i++) {
int len = lengths[i];
if (len != 0) {
symbols[i] = nextCode[len];
nextCode[len]++;
}
}
}
private static void optimizeHuffmanForRle(Cookie cookie, int[] counts) {
int[] goodForRle = cookie.i289a;
int length = counts.length;
for (; length >= 0; --length) {
if (length == 0) {
return;
}
if (counts[length - 1] != 0) {
break;
}
}
System.arraycopy(Cookie.intZeroes, 0, goodForRle, 0, length + 1);
int symbol = counts[0];
int stride = 0;
for (int i = 0; i < length + 1; ++i) {
if (i == length || counts[i] != symbol) {
if ((symbol == 0 && stride >= 5) || (symbol != 0 && stride >= 7)) {
for (int k = 0; k < stride; ++k) {
goodForRle[i - k - 1] = 1;
}
}
stride = 1;
if (i != length) {
symbol = counts[i];
}
} else {
++stride;
}
}
stride = 0;
int limit = counts[0];
int sum = 0;
for (int i = 0; i < length + 1; ++i) {
if ((i == length) || (goodForRle[i] != 0) || (counts[i] - limit >= 4) || (limit - counts[i] >= 4)) {
if ((stride >= 4) || ((stride >= 3) && (sum == 0))) {
int count = (sum + stride / 2) / stride;
if (count < 1) count = 1;
if (sum == 0) {
count = 0;
}
for (int k = 0; k < stride; ++k) {
counts[i - k - 1] = count;
}
}
stride = 0;
sum = 0;
if (i < length - 3) {
limit = (counts[i] + counts[i + 1] + counts[i + 2] + counts[i + 3] + 2) / 4;
} else if (i < length) {
limit = counts[i];
} else {
limit = 0;
}
}
++stride;
if (i != length) {
sum += counts[i];
}
}
}
}

View File

@ -0,0 +1,136 @@
/*
Copyright 2014 Google Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
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.
Author: eustas.ru@gmail.com (Eugene Klyuchnikov)
*/
package net.sourceforge.plantuml.zopfli;
class Hash {
// HASH_SHIFT = 5;
// HASH_MASK = 32767;
private static final int[] seq = new int[0x8000];
static {
int[] seq = Hash.seq;
for (int i = 0, l = 0x8000; i < l; ++i) {
seq[i] = i;
}
}
final int[] head = new int[0x10000];
final int[] prev = new int[0x8000];
private final int[] hashVal = new int[0x8000];
final int[] same = new int[0x8000];
int val;
private final int[] head2 = new int[0x10000];
final int[] prev2 = new int[0x8000];
final int[] hashVal2 = new int[0x8000];
public Hash() {
}
public void init(byte[] input, int windowStart, int from, int to) {
int[] hashVal = this.hashVal;
int[] head = this.head;
int[] same = this.same;
int[] prev = this.prev;
int[] hashVal2 = this.hashVal2;
int[] head2 = this.head2;
int[] prev2 = this.prev2;
System.arraycopy(Cookie.intMOnes, 0, head, 0, 0x10000);
System.arraycopy(Cookie.intMOnes, 0, hashVal, 0, 0x8000);
System.arraycopy(Cookie.intZeroes, 0, same, 0x8000, 0);
System.arraycopy(seq, 0, prev, 0, 0x8000);
System.arraycopy(Cookie.intMOnes, 0, head2, 0, 0x10000);
System.arraycopy(Cookie.intMOnes, 0, hashVal2, 0, 0x8000);
System.arraycopy(seq, 0, prev2, 0, 0x8000);
int val = (((input[windowStart] & 0xFF) << 5) ^ input[windowStart + 1] & 0xFF) & 0x7FFF;
for (int i = windowStart; i < from; ++i) {
int hPos = i & 0x7FFF;
val = ((val << 5) ^ (i + 2 < to ? input[i + 2] & 0xFF : 0)) & 0x7FFF;
hashVal[hPos] = val;
int tmp = head[val];
prev[hPos] = tmp != -1 && hashVal[tmp] == val ? tmp : hPos;
head[val] = hPos;
tmp = same[(i - 1) & 0x7FFF];
if (tmp < 1) {
tmp = 1;
}
tmp += i;
byte b = input[i];
while (tmp < to && b == input[tmp]) {
tmp++;
}
tmp -= i;
tmp--;
same[hPos] = tmp;
tmp = ((tmp - 3) & 0xFF) ^ val;
hashVal2[hPos] = tmp;
int h = head2[tmp];
prev2[hPos] = h != -1 && hashVal2[h] == tmp ? h : hPos;
head2[tmp] = hPos;
}
this.val = val;
}
/*private void updateHashValue(int c) {
val = ((val << HASH_SHIFT) ^ c) & HASH_MASK;
}*/
public void updateHash(byte[] input, int pos, int end) {
// WINDOW_MASK
int hPos = pos & 0x7FFF;
int val = this.val;
val = ((val << 5) ^ (pos + 2 < end ? input[pos + 2] & 0xFF : 0)) & 0x7FFF;
hashVal[hPos] = val;
int tmp = head[val];
prev[hPos] = (tmp != -1 && hashVal[tmp] == val) ? tmp : hPos;
head[val] = hPos;
tmp = same[(pos - 1) & 0x7FFF];
if (tmp < 1) {
tmp = 1;
}
tmp += pos;
byte b = input[pos];
while (tmp < end && b == input[tmp]) {
tmp++;
}
tmp -= pos;
tmp--;
same[hPos] = tmp;
tmp = ((tmp - 3) & 0xFF) ^ val;
hashVal2[hPos] = tmp;
int h = head2[tmp];
prev2[hPos] = h != -1 && hashVal2[h] == tmp ? h : hPos;
head2[tmp] = hPos;
this.val = val;
}
}

View File

@ -0,0 +1,124 @@
/*
Copyright 2014 Google Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
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.
Author: eustas.ru@gmail.com (Eugene Klyuchnikov)
*/
package net.sourceforge.plantuml.zopfli;
import net.sourceforge.plantuml.zopfli.Cookie.Node;
class Katajainen {
static void lengthLimitedCodeLengths(Cookie cookie, int[] frequencies, int maxBits,
int[] bitLengths) {
cookie.resetPool();
int n = frequencies.length;
int nn = 0;
Node[] leaves = cookie.leaves1;
for (int i = 0; i < n; i++) {
if (frequencies[i] != 0) {
leaves[nn] = cookie.node(frequencies[i], i, null);
nn++;
}
}
if (nn == 0) {
return;
}
if (nn == 1) {
bitLengths[leaves[0].count] = 1;
return;
}
Node[] leaves2 = cookie.leaves2;
System.arraycopy(leaves, 0, leaves2, 0, nn);
sort(leaves2, leaves, 0, nn);
Node[] list0 = cookie.list0;
Node node0 = cookie.node(leaves[0].weight, 1, null);
Node[] list1 = cookie.list1;
Node node1 = cookie.node(leaves[1].weight, 2, null);
for (int i = 0; i < maxBits; ++i) {
list0[i] = node0;
list1[i] = node1;
}
int numBoundaryPmRuns = 2 * nn - 4;
for (int i = 0; i < numBoundaryPmRuns; i++) {
boolean last = i == numBoundaryPmRuns - 1;
boundaryPm(cookie, leaves, list0, list1, nn, maxBits - 1, last);
}
for (Node node = list1[maxBits - 1]; node != null; node = node.tail) {
for (int i = node.count - 1; i >= 0; --i) {
bitLengths[leaves[i].count]++;
}
}
}
private static void boundaryPm(Cookie cookie, Node[] leaves, Node[] list0, Node[] list1, int numSymbols, int index,
boolean last) {
int lastCount = list1[index].count;
if (index == 0 && lastCount >= numSymbols) {
return;
}
list0[index] = list1[index];
if (index == 0) {
list1[index] = cookie.node(leaves[lastCount].weight, lastCount + 1, null);
} else {
int sum = list0[index - 1].weight + list1[index - 1].weight;
if (lastCount < numSymbols && sum > leaves[lastCount].weight) {
list1[index] = cookie.node(leaves[lastCount].weight, lastCount + 1, list1[index].tail);
} else {
list1[index] = cookie.node(sum, lastCount, list1[index - 1]);
if (!last) {
boundaryPm(cookie, leaves, list0, list1, numSymbols, index - 1, false);
boundaryPm(cookie, leaves, list0, list1, numSymbols, index - 1, false);
}
}
}
}
private static void sort(Node[] src, Node[] dest, int low, int high) {
int length = high - low;
if (length < 7) {
for (int i = low + 1; i < high; i++)
for (int j = i, k = i - 1; j > low && (dest[k].weight > dest[j].weight); --j, --k) {
Node t = dest[j];
dest[j] = dest[k];
dest[k] = t;
}
return;
}
int mid = (low + high) >>> 1;
sort(dest, src, low, mid);
sort(dest, src, mid, high);
for (int i = low, p = low, q = mid; i < high; i++) {
if (q >= high || p < mid && (src[p].weight <= src[q].weight))
dest[i] = src[p++];
else
dest[i] = src[q++];
}
}
}

View File

@ -0,0 +1,126 @@
/*
Copyright 2014 Google Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
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.
Author: eustas.ru@gmail.com (Eugene Klyuchnikov)
*/
package net.sourceforge.plantuml.zopfli;
class LongestMatchCache {
private final static int CACHE_LENGTH = 8;
public final char[] length;
public final char[] dist;
private final char[] subLenPos;
private final byte[] subLenLen;
LongestMatchCache(int maxBlockSize) {
length = new char[maxBlockSize];
dist = new char[maxBlockSize];
subLenPos = new char[CACHE_LENGTH * maxBlockSize];
subLenLen = new byte[CACHE_LENGTH * maxBlockSize];
}
void init(int blockSize) {
Cookie.fill0(dist, blockSize);
int n = blockSize << 3; // * CACHE_LENGTH
char[] subLenPos = this.subLenPos;
byte[] subLenLen = this.subLenLen;
char[] length = this.length;
char[] charZeroes = Cookie.charZeroes;
byte[] byteZeroes = Cookie.byteZeroes;
char[] charOnes = Cookie.charOnes;
int i = 0;
while (i < n) {
int j = i + 65536;
if (j > n) {
j = n;
}
int l = j - i;
System.arraycopy(byteZeroes, 0, subLenLen, i, l);
System.arraycopy(charZeroes, 0, subLenPos, i, l);
i = j;
}
i = 0;
while (i < blockSize) {
int j = i + 65536;
if (j > blockSize) {
j = blockSize;
}
int l = j - i;
System.arraycopy(charOnes, 0, length, i, l);
System.arraycopy(charZeroes, 0, subLenPos, i, l);
i = j;
}
}
void subLenToCache(char[] input, int pos, int len) {
if (len < 3) {
return;
}
int bestLength = 0;
int j = pos * CACHE_LENGTH;
int last = j + CACHE_LENGTH - 1;
for (int i = 3; i <= len; ++i) {
if (i == len || input[i] != input[i + 1]) {
subLenPos[j] = input[i];
subLenLen[j] = (byte) (i - 3);
bestLength = i;
j++;
if (j > last) {
break;
}
}
}
if (j <= last) {
subLenLen[last] = (byte) (bestLength - 3);
}
}
void cacheToSubLen(int pos, int len, char[] output) {
if (len < 3) {
return;
}
int maxLength = maxCachedSubLen(pos);
int prevLength = 0;
int j = CACHE_LENGTH * pos;
int last = j + CACHE_LENGTH;
for (; j < last; ++j) {
int cLen = (subLenLen[j] & 0xFF) + 3;
char dist = subLenPos[j];
for (int i = prevLength; i <= cLen; ++i) {
output[i] = dist;
}
if (cLen == maxLength) {
break;
}
prevLength = cLen + 1;
}
}
int maxCachedSubLen(int pos) {
pos = pos * CACHE_LENGTH;
if (subLenPos[pos] == 0) {
return 0;
}
return (subLenLen[pos + CACHE_LENGTH - 1] & 0xFF) + 3;
}
}

View File

@ -0,0 +1,45 @@
/*
Copyright 2014 Google Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
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.
Author: eustas.ru@gmail.com (Eugene Klyuchnikov)
*/
package net.sourceforge.plantuml.zopfli;
final class LzStore {
final char[] litLens;
final char[] dists;
int size;
LzStore(final int maxBlockSize) {
litLens = new char[maxBlockSize];
dists = new char[maxBlockSize];
}
final void append(final char length, final char dist) {
litLens[size] = length;
dists[size++] = dist;
}
final void reset() {
size = 0;
}
final void copy(final LzStore source) {
size = source.size;
System.arraycopy(source.litLens, 0, litLens, 0, size);
System.arraycopy(source.dists, 0, dists, 0, size);
}
}

View File

@ -0,0 +1,48 @@
/*
Copyright 2014 Google Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
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.
Author: eustas.ru@gmail.com (Eugene Klyuchnikov)
*/
package net.sourceforge.plantuml.zopfli;
public class Options {
public static enum BlockSplitting {
FIRST,
LAST,
NONE
}
public static enum OutputFormat {
DEFLATE,
GZIP,
ZLIB
}
public final int numIterations;
public final BlockSplitting blockSplitting;
public final OutputFormat outputType;
public Options(OutputFormat outputType, BlockSplitting blockSplitting,
int numIterations) {
this.outputType = outputType;
this.blockSplitting = blockSplitting;
this.numIterations = numIterations;
}
public Options() {
this(OutputFormat.GZIP, BlockSplitting.FIRST, 15);
}
}

View File

@ -0,0 +1,241 @@
/*
Copyright 2014 Google Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
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.
Author: eustas.ru@gmail.com (Eugene Klyuchnikov)
*/
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;
}
}
}
}
}

View File

@ -0,0 +1,181 @@
/*
Copyright 2014 Google Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
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.
Author: eustas.ru@gmail.com (Eugene Klyuchnikov)
*/
package net.sourceforge.plantuml.zopfli;
final class SymbolStats {
private final static double INV_LOG_2 = 1.4426950408889 * 0x10000L; /* 1.0 / log(2.0) */
private final int[] litLens = new int[288];
private final int[] dists = new int[32]; // Why 32? Expect 30.
final long[] lLiterals = new long[288];
final long[] lLengths = new long[259];
final long[] dSymbols = new long[32];
void getFreqs(LzStore store) {
int[] sLitLens = this.litLens;
int[] sDists = this.dists;
System.arraycopy(Cookie.intZeroes, 0, sLitLens, 0, 288);
System.arraycopy(Cookie.intZeroes, 0, sDists, 0, 32);
int size = store.size;
char[] litLens = store.litLens;
char[] dists = store.dists;
int[] lengthSymbol = Util.LENGTH_SYMBOL;
int[] cachedDistSymbol = Util.CACHED_DIST_SYMBOL;
for (int i = 0; i < size; i++) {
int d = dists[i];
int l = litLens[i];
if (d == 0) {
sLitLens[l]++;
} else {
sLitLens[lengthSymbol[l]]++;
sDists[cachedDistSymbol[d]]++;
}
}
sLitLens[256] = 1;
calculate();
}
final void copy(final SymbolStats source) {
System.arraycopy(source.litLens, 0, litLens, 0, 288);
System.arraycopy(source.dists, 0, dists, 0, 32);
System.arraycopy(source.lLiterals, 0, lLiterals, 0, 288);
System.arraycopy(source.lLengths, 0, lLengths, 0, 259);
System.arraycopy(source.dSymbols, 0, dSymbols, 0, 32);
}
final void calculate() {
calculateLens();
calculateDists();
}
final void calculateLens() {
int sum = 0;
int[] litLens = this.litLens;
for (int i = 0; i < 288; ++i) {
sum += litLens[i];
}
double log2sum = (sum == 0 ? Math.log(288) : Math.log(sum)) * INV_LOG_2;
long[] lLiterals = this.lLiterals;
for (int i = 0; i < 288; ++i) {
if (litLens[i] == 0) {
lLiterals[i] = (long)log2sum;
} else {
lLiterals[i] = (long)(log2sum - Math.log(litLens[i]) * INV_LOG_2);
}
if (lLiterals[i] < 0) {
lLiterals[i] = 0;
}
}
long[] lLengths = this.lLengths;
int[] lengthSymbol = Util.LENGTH_SYMBOL;
int[] lengthExtraBits = Util.LENGTH_EXTRA_BITS;
for (int i = 0; i < 259; ++i) {
lLengths[i] = lLiterals[lengthSymbol[i]] + (lengthExtraBits[i] * 0x10000L);
}
}
final void calculateDists() {
int sum = 0;
int[] dists = this.dists;
for (int i = 0; i < 32; ++i) {
sum += dists[i];
}
double log2sum = (sum == 0 ? Math.log(32) : Math.log(sum)) * INV_LOG_2;
long[] dSymbols = this.dSymbols;
for (int i = 0; i < 32; ++i) {
if (dists[i] == 0) {
dSymbols[i] = (long)log2sum;
} else {
dSymbols[i] = (long)(log2sum - Math.log(dists[i]) * INV_LOG_2);
}
if (dSymbols[i] < 0) {
dSymbols[i] = 0;
}
}
for (int i = 4; i < 30; ++i) {
dSymbols[i] += 0x10000L * ((i / 2) - 1);
}
}
final void alloy(final SymbolStats ligand) {
int[] ligandLitLens = ligand.litLens;
for (int i = 0; i < 288; i++) {
litLens[i] += ligandLitLens[i] / 2;
}
litLens[256] = 1;
int[] ligandDists = ligand.dists;
for (int i = 0; i < 32; i++) {
dists[i] += ligandDists[i] / 2;
}
}
final int randomizeFreqs(int z) {
int[] data = litLens;
int n = data.length;
for (int i = 0; i < n; i++) {
z = 0x7FFFFFFF & (1103515245 * z + 12345);
if ((z >>> 4) % 3 == 0) {
z = 0x7FFFFFFF & (1103515245 * z + 12345);
int p = z % n;
if (data[i] < data[p]) {
data[i] = data[p];
}
}
}
data[256] = 1;
data = dists;
n = data.length;
for (int i = 0; i < n; i++) {
z = 0x7FFFFFFF & (1103515245 * z + 12345);
if ((z >>> 4) % 3 == 0) {
z = 0x7FFFFFFF & (1103515245 * z + 12345);
int p = z % n;
if (data[i] < data[p]) {
data[i] = data[p];
}
}
}
return z;
}
final long minCost() {
long[] lLengths = this.lLengths;
long minLengthCost = lLengths[3];
for (int i = 4; i < 259; i++) {
long c = lLengths[i];
if (c < minLengthCost) {
minLengthCost = c;
}
}
long[] dSymbols = this.dSymbols;
long minDistCost = dSymbols[0];
for (int i = 1; i < 30; i++) {
long c = dSymbols[i];
if (c < minDistCost) {
minDistCost = c;
}
}
return minDistCost + minLengthCost;
}
}

View File

@ -0,0 +1,226 @@
/*
Copyright 2014 Google Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
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.
Author: eustas.ru@gmail.com (Eugene Klyuchnikov)
*/
package net.sourceforge.plantuml.zopfli;
class Util {
static final int[] LENGTH_SYMBOL = new int[]{
0, 0, 0,
257, 258, 259, 260, 261, 262, 263, 264,
265, 265,
266, 266,
267, 267,
268, 268,
269, 269, 269, 269,
270, 270, 270, 270,
271, 271, 271, 271,
272, 272, 272, 272,
273, 273, 273, 273, 273, 273, 273, 273,
274, 274, 274, 274, 274, 274, 274, 274,
275, 275, 275, 275, 275, 275, 275, 275,
276, 276, 276, 276, 276, 276, 276, 276,
277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277,
278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278,
279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279,
280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280,
281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281,
282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282,
283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283,
284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284,
285
};
static final int[] LENGTH_EXTRA_BITS = new int[]{
0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
1, 1,
1, 1,
1, 1,
1, 1,
2, 2, 2, 2,
2, 2, 2, 2,
2, 2, 2, 2,
2, 2, 2, 2,
3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
0
};
static final int[] LENGTH_EXTRA_BITS_VALUE = new int[]{
0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 1,
0, 1,
0, 1,
0, 1,
0, 1, 2, 3,
0, 1, 2, 3,
0, 1, 2, 3,
0, 1, 2, 3,
0, 1, 2, 3, 4, 5, 6, 7,
0, 1, 2, 3, 4, 5, 6, 7,
0, 1, 2, 3, 4, 5, 6, 7,
0, 1, 2, 3, 4, 5, 6, 7,
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30,
0
};
static final int[] ORDER = new int[]{
16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15
};
static final int[] CACHED_DIST_SYMBOL = cacheDistSymbol();
private static int[] cacheDistSymbol() {
int[] r = new int[32768];
for (int i = 0; i < 32768; ++i) {
r[i] = distSymbol(i);
}
return r;
}
private static int distSymbol(int dist) {
if (dist < 193) {
if (dist < 13) { /* dist 0..13. */
if (dist < 5) return dist - 1;
else if (dist < 7) return 4;
else if (dist < 9) return 5;
else return 6;
} else { /* dist 13..193. */
if (dist < 17) return 7;
else if (dist < 25) return 8;
else if (dist < 33) return 9;
else if (dist < 49) return 10;
else if (dist < 65) return 11;
else if (dist < 97) return 12;
else if (dist < 129) return 13;
else return 14;
}
} else {
if (dist < 2049) { /* dist 193..2049. */
if (dist < 257) return 15;
else if (dist < 385) return 16;
else if (dist < 513) return 17;
else if (dist < 769) return 18;
else if (dist < 1025) return 19;
else if (dist < 1537) return 20;
else return 21;
} else { /* dist 2049..32768. */
if (dist < 3073) return 22;
else if (dist < 4097) return 23;
else if (dist < 6145) return 24;
else if (dist < 8193) return 25;
else if (dist < 12289) return 26;
else if (dist < 16385) return 27;
else if (dist < 24577) return 28;
else return 29;
}
}
}
static final int[] CACHED_DIST_EXTRA_BITS = precacheDistExtraBits();
private static int[] precacheDistExtraBits() {
int[] r = new int[4097];
for (int i = 0; i < 4097; ++i) {
r[i] = distExtraBits(i);
}
return r;
}
private static int distExtraBits(int dist) {
if (dist < 5) {
return 0;
} else if (dist < 9) {
return 1;
} else if (dist < 17) {
return 2;
} else if (dist < 33) {
return 3;
} else if (dist < 65) {
return 4;
} else if (dist < 129) {
return 5;
} else if (dist < 257) {
return 6;
} else if (dist < 513) {
return 7;
} else if (dist < 1025) {
return 8;
} else if (dist < 2049) {
return 9;
} else if (dist < 4097) {
return 10;
} else if (dist < 8193) {
return 11;
} else if (dist < 16385) {
return 12;
}
return 13;
}
static int distExtraBitsValue(int dist) {
if (dist < 5) {
return 0;
} else if (dist < 9) {
return (dist - 5) & 1;
} else if (dist < 17) {
return (dist - 9) & 3;
} else if (dist < 33) {
return (dist - 17) & 7;
} else if (dist < 65) {
return (dist - 33) & 15;
} else if (dist < 129) {
return (dist - 65) & 31;
} else if (dist < 257) {
return (dist - 129) & 63;
} else if (dist < 513) {
return (dist - 257) & 127;
} else if (dist < 1025) {
return (dist - 513) & 255;
} else if (dist < 2049) {
return (dist - 1025) & 511;
} else if (dist < 4097) {
return (dist - 2049) & 1023;
} else if (dist < 8193) {
return (dist - 4097) & 2047;
} else if (dist < 16385) {
return (dist - 8193) & 4095;
}
return (dist - 16385) & 8191;
}
}

View File

@ -0,0 +1,144 @@
/*
Copyright 2014 Google Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
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.
Author: eustas.ru@gmail.com (Eugene Klyuchnikov)
*/
package net.sourceforge.plantuml.zopfli;
public class Zopfli {
private static class Crc {
private final static int[] table = makeTable();
private static int[] makeTable() {
int[] result = new int[256];
for (int n = 0; n < 256; ++n) {
int c = n;
for (int k = 0; k < 8; ++k) {
if ((c & 1) == 1) {
c = 0xEDB88320 ^ (c >>> 1);
} else {
c = c >>> 1;
}
}
result[n] = c;
}
return result;
}
public static int calculate(byte[] input) {
int c = ~0;
for (int i = 0, n = input.length; i < n; ++i) {
c = table[(c ^ input[i]) & 0xFF] ^ (c >>> 8);
}
return ~c;
}
}
private final Cookie cookie;
public synchronized Buffer compress(Options options, byte[] input) {
Buffer output = new Buffer();
switch (options.outputType) {
case GZIP:
compressGzip(options, input, output);
break;
case ZLIB:
compressZlib(options, input, output);
break;
case DEFLATE:
Deflate.compress(cookie, options, input, output);
break;
default:
throw new IllegalArgumentException(
"Unexpected output format: " + options.outputType);
}
return output;
}
/**
* Calculates the adler32 checksum of the data
*/
private static int adler32(byte[] data) {
int s1 = 1;
int s2 = 1 >> 16;
int i = 0;
while (i < data.length) {
int tick = Math.min(data.length, i + 1024);
while (i < tick) {
s1 += data[i++];
s2 += s1;
}
s1 %= 65521;
s2 %= 65521;
}
return (s2 << 16) | s1;
}
private void compressZlib(Options options, byte[] input,
Buffer output) {
output.append((byte) 0x78);
output.append((byte) 0x1E);
Deflate.compress(cookie, options, input, output);
int checksum = adler32(input);
output.append((byte) ((checksum >> 24) & 0xFF));
output.append((byte) ((checksum >> 16) & 0xFF));
output.append((byte) ((checksum >> 8) & 0xFF));
output.append((byte) (checksum & 0xFF));
}
private void compressGzip(Options options, byte[] input,
Buffer output) {
output.append((byte) 31);
output.append((byte) 139);
output.append((byte) 8);
output.append((byte) 0);
output.append((byte) 0);
output.append((byte) 0);
output.append((byte) 0);
output.append((byte) 0);
output.append((byte) 2);
output.append((byte) 3);
Deflate.compress(cookie, options, input, output);
int crc = Crc.calculate(input);
output.append((byte) (crc & 0xFF));
output.append((byte) ((crc >> 8) & 0xFF));
output.append((byte) ((crc >> 16) & 0xFF));
output.append((byte) ((crc >> 24) & 0xFF));
int size = input.length;
output.append((byte) (size & 0xFF));
output.append((byte) ((size >> 8) & 0xFF));
output.append((byte) ((size >> 16) & 0xFF));
output.append((byte) ((size >> 24) & 0xFF));
}
public Zopfli(int masterBlockSize) {
cookie = new Cookie(masterBlockSize);
}
}

View File

@ -0,0 +1,269 @@
/* Copyright 2015 Google Inc. All Rights Reserved.
Distributed under MIT license.
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
*/
package org.brotli.dec;
/**
* Bit reading helpers.
*/
final class BitReader {
// Added by Arnaud... not very beautifull
private static final boolean CHECK_UNUSED_BYTES_AFTER_END = false;
// Possible values: {5, 6}. 5 corresponds to 32-bit build, 6 to 64-bit. This value is used for
// conditional compilation -> produced artifacts might be binary INCOMPATIBLE (JLS 13.2).
private static final int LOG_BITNESS = 6;
private static final int BITNESS = 1 << LOG_BITNESS;
private static final int BYTENESS = BITNESS / 8;
private static final int CAPACITY = 4096;
// After encountering the end of the input stream, this amount of zero bytes will be appended.
private static final int SLACK = 64;
private static final int BUFFER_SIZE = CAPACITY + SLACK;
// Don't bother to replenish the buffer while this number of bytes is available.
private static final int SAFEGUARD = 36;
private static final int WATERLINE = CAPACITY - SAFEGUARD;
// "Half" refers to "half of native integer type", i.e. on 64-bit machines it is 32-bit type,
// on 32-bit machines it is 16-bit.
private static final int HALF_BITNESS = BITNESS / 2;
private static final int HALF_SIZE = BYTENESS / 2;
private static final int HALVES_CAPACITY = CAPACITY / HALF_SIZE;
private static final int HALF_BUFFER_SIZE = BUFFER_SIZE / HALF_SIZE;
private static final int HALF_WATERLINE = WATERLINE / HALF_SIZE;
private static final int LOG_HALF_SIZE = LOG_BITNESS - 4;
/**
* Fills up the input buffer.
*
* <p> No-op if there are at least 36 bytes present after current position.
*
* <p> After encountering the end of the input stream, 64 additional zero bytes are copied to the
* buffer.
*/
static void readMoreInput(State s) {
if (s.halfOffset > HALF_WATERLINE) {
doReadMoreInput(s);
}
}
static void doReadMoreInput(State s) {
if (s.endOfStreamReached != 0) {
if (halfAvailable(s) >= -2) {
return;
}
throw new BrotliRuntimeException("No more input");
}
int readOffset = s.halfOffset << LOG_HALF_SIZE;
int bytesInBuffer = CAPACITY - readOffset;
// Move unused bytes to the head of the buffer.
Utils.copyBytesWithin(s.byteBuffer, 0, readOffset, CAPACITY);
s.halfOffset = 0;
while (bytesInBuffer < CAPACITY) {
int spaceLeft = CAPACITY - bytesInBuffer;
int len = Utils.readInput(s.input, s.byteBuffer, bytesInBuffer, spaceLeft);
// EOF is -1 in Java, but 0 in C#.
if (len <= 0) {
s.endOfStreamReached = 1;
s.tailBytes = bytesInBuffer;
bytesInBuffer += HALF_SIZE - 1;
break;
}
bytesInBuffer += len;
}
bytesToNibbles(s, bytesInBuffer);
}
static void checkHealth(State s, int endOfStream) {
if (s.endOfStreamReached == 0) {
return;
}
int byteOffset = (s.halfOffset << LOG_HALF_SIZE) + ((s.bitOffset + 7) >> 3) - BYTENESS;
if (byteOffset > s.tailBytes) {
throw new BrotliRuntimeException("Read after end");
}
if (CHECK_UNUSED_BYTES_AFTER_END && (endOfStream != 0) && (byteOffset != s.tailBytes)) {
throw new BrotliRuntimeException("Unused bytes after end");
}
}
static void fillBitWindow(State s) {
if (s.bitOffset >= HALF_BITNESS) {
// Same as doFillBitWindow. JVM fails to inline it.
if (BITNESS == 64) {
s.accumulator64 = ((long) s.intBuffer[s.halfOffset++] << HALF_BITNESS)
| (s.accumulator64 >>> HALF_BITNESS);
} else {
s.accumulator32 = ((int) s.shortBuffer[s.halfOffset++] << HALF_BITNESS)
| (s.accumulator32 >>> HALF_BITNESS);
}
s.bitOffset -= HALF_BITNESS;
}
}
private static void doFillBitWindow(State s) {
if (BITNESS == 64) {
s.accumulator64 = ((long) s.intBuffer[s.halfOffset++] << HALF_BITNESS)
| (s.accumulator64 >>> HALF_BITNESS);
} else {
s.accumulator32 = ((int) s.shortBuffer[s.halfOffset++] << HALF_BITNESS)
| (s.accumulator32 >>> HALF_BITNESS);
}
s.bitOffset -= HALF_BITNESS;
}
static int peekBits(State s) {
if (BITNESS == 64) {
return (int) (s.accumulator64 >>> s.bitOffset);
} else {
return s.accumulator32 >>> s.bitOffset;
}
}
static int readFewBits(State s, int n) {
int val = peekBits(s) & ((1 << n) - 1);
s.bitOffset += n;
return val;
}
static int readBits(State s, int n) {
if (HALF_BITNESS >= 24) {
return readFewBits(s, n);
} else {
return (n <= 16) ? readFewBits(s, n) : readManyBits(s, n);
}
}
private static int readManyBits(State s, int n) {
int low = readFewBits(s, 16);
doFillBitWindow(s);
return low | (readFewBits(s, n - 16) << 16);
}
static void initBitReader(State s) {
s.byteBuffer = new byte[BUFFER_SIZE];
if (BITNESS == 64) {
s.accumulator64 = 0;
s.intBuffer = new int[HALF_BUFFER_SIZE];
} else {
s.accumulator32 = 0;
s.shortBuffer = new short[HALF_BUFFER_SIZE];
}
s.bitOffset = BITNESS;
s.halfOffset = HALVES_CAPACITY;
s.endOfStreamReached = 0;
prepare(s);
}
private static void prepare(State s) {
readMoreInput(s);
checkHealth(s, 0);
doFillBitWindow(s);
doFillBitWindow(s);
}
static void reload(State s) {
if (s.bitOffset == BITNESS) {
prepare(s);
}
}
static void jumpToByteBoundary(State s) {
int padding = (BITNESS - s.bitOffset) & 7;
if (padding != 0) {
int paddingBits = readFewBits(s, padding);
if (paddingBits != 0) {
throw new BrotliRuntimeException("Corrupted padding bits");
}
}
}
static int halfAvailable(State s) {
int limit = HALVES_CAPACITY;
if (s.endOfStreamReached != 0) {
limit = (s.tailBytes + (HALF_SIZE - 1)) >> LOG_HALF_SIZE;
}
return limit - s.halfOffset;
}
static void copyBytes(State s, byte[] data, int offset, int length) {
if ((s.bitOffset & 7) != 0) {
throw new BrotliRuntimeException("Unaligned copyBytes");
}
// Drain accumulator.
while ((s.bitOffset != BITNESS) && (length != 0)) {
data[offset++] = (byte) peekBits(s);
s.bitOffset += 8;
length--;
}
if (length == 0) {
return;
}
// Get data from shadow buffer with "sizeof(int)" granularity.
int copyNibbles = Math.min(halfAvailable(s), length >> LOG_HALF_SIZE);
if (copyNibbles > 0) {
int readOffset = s.halfOffset << LOG_HALF_SIZE;
int delta = copyNibbles << LOG_HALF_SIZE;
System.arraycopy(s.byteBuffer, readOffset, data, offset, delta);
offset += delta;
length -= delta;
s.halfOffset += copyNibbles;
}
if (length == 0) {
return;
}
// Read tail bytes.
if (halfAvailable(s) > 0) {
// length = 1..3
fillBitWindow(s);
while (length != 0) {
data[offset++] = (byte) peekBits(s);
s.bitOffset += 8;
length--;
}
checkHealth(s, 0);
return;
}
// Now it is possible to copy bytes directly.
while (length > 0) {
int len = Utils.readInput(s.input, data, offset, length);
if (len == -1) {
throw new BrotliRuntimeException("Unexpected end of input");
}
offset += len;
length -= len;
}
}
/**
* Translates bytes to halves (int/short).
*/
static void bytesToNibbles(State s, int byteLen) {
byte[] byteBuffer = s.byteBuffer;
int halfLen = byteLen >> LOG_HALF_SIZE;
if (BITNESS == 64) {
int[] intBuffer = s.intBuffer;
for (int i = 0; i < halfLen; ++i) {
intBuffer[i] = ((byteBuffer[i * 4] & 0xFF))
| ((byteBuffer[(i * 4) + 1] & 0xFF) << 8)
| ((byteBuffer[(i * 4) + 2] & 0xFF) << 16)
| ((byteBuffer[(i * 4) + 3] & 0xFF) << 24);
}
} else {
short[] shortBuffer = s.shortBuffer;
for (int i = 0; i < halfLen; ++i) {
shortBuffer[i] = (short) ((byteBuffer[i * 2] & 0xFF)
| ((byteBuffer[(i * 2) + 1] & 0xFF) << 8));
}
}
}
}

View File

@ -0,0 +1,150 @@
/* Copyright 2015 Google Inc. All Rights Reserved.
Distributed under MIT license.
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
*/
package org.brotli.dec;
import java.io.IOException;
import java.io.InputStream;
/**
* {@link InputStream} decorator that decompresses brotli data.
*
* <p> Not thread-safe.
*/
public class BrotliInputStream extends InputStream {
public static final int DEFAULT_INTERNAL_BUFFER_SIZE = 16384;
/**
* Internal buffer used for efficient byte-by-byte reading.
*/
private byte[] buffer;
/**
* Number of decoded but still unused bytes in internal buffer.
*/
private int remainingBufferBytes;
/**
* Next unused byte offset.
*/
private int bufferOffset;
/**
* Decoder state.
*/
private final State state = new State();
/**
* Creates a {@link InputStream} wrapper that decompresses brotli data.
*
* <p> For byte-by-byte reading ({@link #read()}) internal buffer with
* {@link #DEFAULT_INTERNAL_BUFFER_SIZE} size is allocated and used.
*
* <p> Will block the thread until first kilobyte of data of source is available.
*
* @param source underlying data source
* @throws IOException in case of corrupted data or source stream problems
*/
public BrotliInputStream(InputStream source) throws IOException {
this(source, DEFAULT_INTERNAL_BUFFER_SIZE);
}
/**
* Creates a {@link InputStream} wrapper that decompresses brotli data.
*
* <p> For byte-by-byte reading ({@link #read()}) internal buffer of specified size is
* allocated and used.
*
* <p> Will block the thread until first kilobyte of data of source is available.
*
* @param source compressed data source
* @param byteReadBufferSize size of internal buffer used in case of
* byte-by-byte reading
* @throws IOException in case of corrupted data or source stream problems
*/
public BrotliInputStream(InputStream source, int byteReadBufferSize) throws IOException {
if (byteReadBufferSize <= 0) {
throw new IllegalArgumentException("Bad buffer size:" + byteReadBufferSize);
} else if (source == null) {
throw new IllegalArgumentException("source is null");
}
this.buffer = new byte[byteReadBufferSize];
this.remainingBufferBytes = 0;
this.bufferOffset = 0;
try {
Decode.initState(state, source);
} catch (BrotliRuntimeException ex) {
throw new IOException("Brotli decoder initialization failed", ex);
}
}
/**
* {@inheritDoc}
*/
@Override
public void close() throws IOException {
Decode.close(state);
}
/**
* {@inheritDoc}
*/
@Override
public int read() throws IOException {
if (bufferOffset >= remainingBufferBytes) {
remainingBufferBytes = read(buffer, 0, buffer.length);
bufferOffset = 0;
if (remainingBufferBytes == -1) {
return -1;
}
}
return buffer[bufferOffset++] & 0xFF;
}
/**
* {@inheritDoc}
*/
@Override
public int read(byte[] destBuffer, int destOffset, int destLen) throws IOException {
if (destOffset < 0) {
throw new IllegalArgumentException("Bad offset: " + destOffset);
} else if (destLen < 0) {
throw new IllegalArgumentException("Bad length: " + destLen);
} else if (destOffset + destLen > destBuffer.length) {
throw new IllegalArgumentException(
"Buffer overflow: " + (destOffset + destLen) + " > " + destBuffer.length);
} else if (destLen == 0) {
return 0;
}
int copyLen = Math.max(remainingBufferBytes - bufferOffset, 0);
if (copyLen != 0) {
copyLen = Math.min(copyLen, destLen);
System.arraycopy(buffer, bufferOffset, destBuffer, destOffset, copyLen);
bufferOffset += copyLen;
destOffset += copyLen;
destLen -= copyLen;
if (destLen == 0) {
return copyLen;
}
}
try {
state.output = destBuffer;
state.outputOffset = destOffset;
state.outputLength = destLen;
state.outputUsed = 0;
Decode.decompress(state);
if (state.outputUsed == 0) {
return -1;
}
return state.outputUsed + copyLen;
} catch (BrotliRuntimeException ex) {
throw new IOException("Brotli stream decoding failed", ex);
}
// <{[INJECTED CODE]}>
}
}

View File

@ -0,0 +1,21 @@
/* Copyright 2015 Google Inc. All Rights Reserved.
Distributed under MIT license.
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
*/
package org.brotli.dec;
/**
* Unchecked exception used internally.
*/
class BrotliRuntimeException extends RuntimeException {
BrotliRuntimeException(String message) {
super(message);
}
BrotliRuntimeException(String message, Throwable cause) {
super(message, cause);
}
}

View File

@ -0,0 +1,58 @@
/* Copyright 2015 Google Inc. All Rights Reserved.
Distributed under MIT license.
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
*/
package org.brotli.dec;
/**
* Common context lookup table for all context modes.
*/
final class Context {
static final int[] LOOKUP = new int[2048];
private static final String UTF_MAP = " !! ! \"#$##%#$&'##(#)#+++++++++"
+ "+((&*'##,---,---,-----,-----,-----&#'###.///.///./////./////./////&#'# ";
private static final String UTF_RLE = "A/* ': & : $ \u0081 @";
private static void unpackLookupTable(int[] lookup, String map, String rle) {
// LSB6, MSB6, SIGNED
for (int i = 0; i < 256; ++i) {
lookup[i] = i & 0x3F;
lookup[512 + i] = i >> 2;
lookup[1792 + i] = 2 + (i >> 6);
}
// UTF8
for (int i = 0; i < 128; ++i) {
lookup[1024 + i] = 4 * (map.charAt(i) - 32);
}
for (int i = 0; i < 64; ++i) {
lookup[1152 + i] = i & 1;
lookup[1216 + i] = 2 + (i & 1);
}
int offset = 1280;
for (int k = 0; k < 19; ++k) {
int value = k & 3;
int rep = rle.charAt(k) - 32;
for (int i = 0; i < rep; ++i) {
lookup[offset++] = value;
}
}
// SIGNED
for (int i = 0; i < 16; ++i) {
lookup[1792 + i] = 1;
lookup[2032 + i] = 6;
}
lookup[1792] = 0;
lookup[2047] = 7;
for (int i = 0; i < 256; ++i) {
lookup[1536 + i] = lookup[1792 + i] << 3;
}
}
static {
unpackLookupTable(LOOKUP, UTF_MAP, UTF_RLE);
}
}

Some files were not shown because too many files have changed in this diff Show More