From 9f224e46f38d3e2339c51b797c59785ace9b4a7f Mon Sep 17 00:00:00 2001 From: Arnaud Roques Date: Fri, 2 Apr 2021 19:26:59 +0200 Subject: [PATCH] Minor correction --- src/net/sourceforge/plantuml/Run.java | 2 + .../plantuml/dedication/NoisyInputStream.java | 72 ++++ .../plantuml/graphic/color/Colors.java | 4 + src/net/sourceforge/plantuml/style/Style.java | 12 + .../svek/CucaDiagramFileMakerSvek.java | 4 +- .../plantuml/svek/GeneralImageBuilder.java | 9 + .../svek/image/EntityImageActivity.java | 2 +- .../plantuml/svek/image/EntityImageClass.java | 2 +- .../svek/image/EntityImageDescription.java | 3 +- .../svek/image/EntityImageEmptyPackage.java | 23 +- .../image/EntityImageLollipopInterface.java | 2 +- .../plantuml/svek/image/EntityImageMap.java | 2 +- .../svek/image/EntityImageObject.java | 2 +- .../plantuml/svek/image/EntityImagePort.java | 2 +- .../plantuml/svek/image/EntityImageTips.java | 2 +- .../plantuml/ugraphic/eps/DriverTextEps.java | 3 +- .../sourceforge/plantuml/utils/MTRandom.java | 390 ++++++++++++++++++ .../sourceforge/plantuml/version/Version.java | 2 +- 18 files changed, 519 insertions(+), 19 deletions(-) create mode 100644 src/net/sourceforge/plantuml/dedication/NoisyInputStream.java create mode 100644 src/net/sourceforge/plantuml/utils/MTRandom.java diff --git a/src/net/sourceforge/plantuml/Run.java b/src/net/sourceforge/plantuml/Run.java index aa7a079cb..b485f81b3 100644 --- a/src/net/sourceforge/plantuml/Run.java +++ b/src/net/sourceforge/plantuml/Run.java @@ -215,6 +215,8 @@ public class Run { if (OptionFlags.getInstance().isGui() == false) { if (error.hasError() || error.isNoData()) { option.getStdrpt().finalMessage(error); + } + if (error.hasError()) { System.exit(error.getExitCode()); } diff --git a/src/net/sourceforge/plantuml/dedication/NoisyInputStream.java b/src/net/sourceforge/plantuml/dedication/NoisyInputStream.java new file mode 100644 index 000000000..d99a894eb --- /dev/null +++ b/src/net/sourceforge/plantuml/dedication/NoisyInputStream.java @@ -0,0 +1,72 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * (C) Copyright 2009-2020, 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.dedication; + +import java.io.IOException; +import java.io.InputStream; + +import net.sourceforge.plantuml.utils.MTRandom; + +public class NoisyInputStream extends InputStream { + + private final MTRandom rnd; + private final InputStream source; + + public NoisyInputStream(InputStream source, byte[] pass) { + this.source = source; + this.rnd = new MTRandom(pass); + } + + private byte getNextByte() { + return (byte) rnd.nextInt(); + } + + @Override + public void close() throws IOException { + source.close(); + } + + @Override + public int read() throws IOException { + int b = source.read(); + if (b == -1) { + return -1; + } + b = (b ^ getNextByte()) & 0xFF; + return b; + } + +} diff --git a/src/net/sourceforge/plantuml/graphic/color/Colors.java b/src/net/sourceforge/plantuml/graphic/color/Colors.java index de8d5a23b..f2e218448 100644 --- a/src/net/sourceforge/plantuml/graphic/color/Colors.java +++ b/src/net/sourceforge/plantuml/graphic/color/Colors.java @@ -44,6 +44,7 @@ import net.sourceforge.plantuml.FontParam; import net.sourceforge.plantuml.ISkinParam; import net.sourceforge.plantuml.SkinParamColors; import net.sourceforge.plantuml.StringUtils; +import net.sourceforge.plantuml.UseStyle; import net.sourceforge.plantuml.cucadiagram.LinkStyle; import net.sourceforge.plantuml.cucadiagram.Stereotype; import net.sourceforge.plantuml.ugraphic.UGraphic; @@ -215,6 +216,9 @@ public class Colors { if (getColor(colorType) != null) { return this; } + if (UseStyle.useBetaStyle()) { + return this; + } final HColor col = skinParam.getFontHtmlColor(stereotype, param); return add(colorType, col); } diff --git a/src/net/sourceforge/plantuml/style/Style.java b/src/net/sourceforge/plantuml/style/Style.java index fbc1e1bcf..0d26b4245 100644 --- a/src/net/sourceforge/plantuml/style/Style.java +++ b/src/net/sourceforge/plantuml/style/Style.java @@ -125,6 +125,10 @@ public class Style { if (line != null) { result = result.eventuallyOverride(PName.LineColor, line); } + final HColor text = colors.getColor(ColorType.TEXT); + if (text != null) { + result = result.eventuallyOverride(PName.FontColor, text); + } } return result; } @@ -184,6 +188,14 @@ public class Style { } } + public UStroke getStroke(Colors colors) { + final UStroke stroke = colors.getSpecificLineStroke(); + if (stroke == null) { + return getStroke(); + } + return stroke; + } + public LineBreakStrategy wrapWidth() { final String value = value(PName.MaximumWidth).asString(); return new LineBreakStrategy(value); diff --git a/src/net/sourceforge/plantuml/svek/CucaDiagramFileMakerSvek.java b/src/net/sourceforge/plantuml/svek/CucaDiagramFileMakerSvek.java index b3019b694..ffb876548 100644 --- a/src/net/sourceforge/plantuml/svek/CucaDiagramFileMakerSvek.java +++ b/src/net/sourceforge/plantuml/svek/CucaDiagramFileMakerSvek.java @@ -35,6 +35,8 @@ */ package net.sourceforge.plantuml.svek; +import static net.sourceforge.plantuml.ugraphic.ImageBuilder.styledImageBuilder; + import java.io.IOException; import java.io.OutputStream; import java.util.ArrayList; @@ -53,8 +55,6 @@ import net.sourceforge.plantuml.cucadiagram.dot.CucaDiagramSimplifierState; import net.sourceforge.plantuml.cucadiagram.dot.DotData; import net.sourceforge.plantuml.graphic.StringBounder; -import static net.sourceforge.plantuml.ugraphic.ImageBuilder.styledImageBuilder; - public final class CucaDiagramFileMakerSvek implements CucaDiagramFileMaker { private final CucaDiagram diagram; diff --git a/src/net/sourceforge/plantuml/svek/GeneralImageBuilder.java b/src/net/sourceforge/plantuml/svek/GeneralImageBuilder.java index e78265631..250e3c222 100644 --- a/src/net/sourceforge/plantuml/svek/GeneralImageBuilder.java +++ b/src/net/sourceforge/plantuml/svek/GeneralImageBuilder.java @@ -142,6 +142,15 @@ public final class GeneralImageBuilder { public static IEntityImage createEntityImageBlock(ILeaf leaf, ISkinParam skinParam, boolean isHideEmptyDescriptionForState, PortionShower portionShower, Bibliotekon bibliotekon, GraphvizVersion graphvizVersion, UmlDiagramType umlDiagramType, Collection links) { + final IEntityImage result = createEntityImageBlockInternal(leaf, skinParam, isHideEmptyDescriptionForState, + portionShower, bibliotekon, graphvizVersion, umlDiagramType, links); + // System.err.println("leaf " + leaf + " " + result.getClass()); + return result; + } + + private static IEntityImage createEntityImageBlockInternal(ILeaf leaf, ISkinParam skinParam, + boolean isHideEmptyDescriptionForState, PortionShower portionShower, Bibliotekon bibliotekon, + GraphvizVersion graphvizVersion, UmlDiagramType umlDiagramType, Collection links) { if (leaf.isRemoved()) { throw new IllegalStateException(); } diff --git a/src/net/sourceforge/plantuml/svek/image/EntityImageActivity.java b/src/net/sourceforge/plantuml/svek/image/EntityImageActivity.java index 7d62fe258..4c60fc5b9 100644 --- a/src/net/sourceforge/plantuml/svek/image/EntityImageActivity.java +++ b/src/net/sourceforge/plantuml/svek/image/EntityImageActivity.java @@ -57,8 +57,8 @@ import net.sourceforge.plantuml.style.Style; import net.sourceforge.plantuml.style.StyleSignature; import net.sourceforge.plantuml.svek.AbstractEntityImage; import net.sourceforge.plantuml.svek.Bibliotekon; -import net.sourceforge.plantuml.svek.SvekNode; import net.sourceforge.plantuml.svek.ShapeType; +import net.sourceforge.plantuml.svek.SvekNode; import net.sourceforge.plantuml.ugraphic.Shadowable; import net.sourceforge.plantuml.ugraphic.UGraphic; import net.sourceforge.plantuml.ugraphic.URectangle; diff --git a/src/net/sourceforge/plantuml/svek/image/EntityImageClass.java b/src/net/sourceforge/plantuml/svek/image/EntityImageClass.java index 37609bf49..1c8a888a1 100644 --- a/src/net/sourceforge/plantuml/svek/image/EntityImageClass.java +++ b/src/net/sourceforge/plantuml/svek/image/EntityImageClass.java @@ -71,10 +71,10 @@ import net.sourceforge.plantuml.ugraphic.Shadowable; import net.sourceforge.plantuml.ugraphic.UComment; import net.sourceforge.plantuml.ugraphic.UGraphic; import net.sourceforge.plantuml.ugraphic.UGraphicStencil; +import net.sourceforge.plantuml.ugraphic.UGroupType; import net.sourceforge.plantuml.ugraphic.URectangle; import net.sourceforge.plantuml.ugraphic.UStroke; import net.sourceforge.plantuml.ugraphic.UTranslate; -import net.sourceforge.plantuml.ugraphic.UGroupType; import net.sourceforge.plantuml.ugraphic.color.HColor; import net.sourceforge.plantuml.ugraphic.color.HColorNone; diff --git a/src/net/sourceforge/plantuml/svek/image/EntityImageDescription.java b/src/net/sourceforge/plantuml/svek/image/EntityImageDescription.java index 0218bca42..83ff6d1a7 100644 --- a/src/net/sourceforge/plantuml/svek/image/EntityImageDescription.java +++ b/src/net/sourceforge/plantuml/svek/image/EntityImageDescription.java @@ -144,6 +144,7 @@ public class EntityImageDescription extends AbstractEntityImage { final StyleSignature tmp = StyleSignature.of(SName.root, SName.element, styleName, symbol.getSkinParameter().getStyleName()); style = tmp.with(stereotype).getMergedStyle(getSkinParam().getCurrentStyleBuilder()); + style = style.eventuallyOverride(colors); final Style styleStereo = tmp.withStereotype(stereotype) .getMergedStyle(getSkinParam().getCurrentStyleBuilder()); forecolor = style.value(PName.LineColor).asColor(getSkinParam().getIHtmlColorSet()); @@ -153,7 +154,7 @@ public class EntityImageDescription extends AbstractEntityImage { roundCorner = style.value(PName.RoundCorner).asDouble(); diagonalCorner = style.value(PName.DiagonalCorner).asDouble(); deltaShadow = style.value(PName.Shadowing).asDouble(); - stroke = style.getStroke(); + stroke = style.getStroke(colors); fcTitle = style.getFontConfiguration(getSkinParam().getIHtmlColorSet()); fcStereo = styleStereo.getFontConfiguration(getSkinParam().getIHtmlColorSet()); defaultAlign = style.getHorizontalAlignment(); diff --git a/src/net/sourceforge/plantuml/svek/image/EntityImageEmptyPackage.java b/src/net/sourceforge/plantuml/svek/image/EntityImageEmptyPackage.java index 29e362227..2ed2ea301 100644 --- a/src/net/sourceforge/plantuml/svek/image/EntityImageEmptyPackage.java +++ b/src/net/sourceforge/plantuml/svek/image/EntityImageEmptyPackage.java @@ -60,6 +60,7 @@ import net.sourceforge.plantuml.graphic.StringBounder; import net.sourceforge.plantuml.graphic.TextBlock; import net.sourceforge.plantuml.graphic.TextBlockUtils; import net.sourceforge.plantuml.graphic.color.ColorType; +import net.sourceforge.plantuml.graphic.color.Colors; import net.sourceforge.plantuml.style.PName; import net.sourceforge.plantuml.style.SName; import net.sourceforge.plantuml.style.Style; @@ -93,38 +94,46 @@ public class EntityImageEmptyPackage extends AbstractEntityImage { } private StyleSignature getDefaultStyleDefinition() { - return StyleSignature.of(SName.root, SName.element, styleName, SName.package_); + return StyleSignature.of(SName.root, SName.element, styleName, SName.package_).with(stereotype); } public EntityImageEmptyPackage(ILeaf entity, ISkinParam skinParam, PortionShower portionShower, SName styleName) { super(entity, skinParam); this.styleName = styleName; - final HColor specificBackColor = entity.getColors(skinParam).getColor(ColorType.BACK); + final Colors colors = entity.getColors(getSkinParam()); + final HColor specificBackColor = colors.getColor(ColorType.BACK); this.stereotype = entity.getStereotype(); - this.desc = entity.getDisplay().create(new FontConfiguration(getSkinParam(), FontParam.PACKAGE, stereotype), - HorizontalAlignment.CENTER, skinParam); + final FontConfiguration titleFontConfiguration; + final HorizontalAlignment titleHorizontalAlignment; this.url = entity.getUrl99(); if (UseStyle.useBetaStyle()) { - final Style style = getStyle(); + Style style = getStyle(); + style = style.eventuallyOverride(colors); this.borderColor = style.value(PName.LineColor).asColor(getSkinParam().getIHtmlColorSet()); this.shadowing = style.value(PName.Shadowing).asDouble(); - this.stroke = style.getStroke(); + this.stroke = style.getStroke(colors); this.roundCorner = style.value(PName.RoundCorner).asDouble(); if (specificBackColor == null) { this.back = style.value(PName.BackGroundColor).asColor(getSkinParam().getIHtmlColorSet()); } else { this.back = specificBackColor; } + titleFontConfiguration = style.getFontConfiguration(getSkinParam().getIHtmlColorSet()); + titleHorizontalAlignment = style.getHorizontalAlignment(); } else { this.borderColor = SkinParamUtils.getColor(getSkinParam(), getStereo(), ColorParam.packageBorder); this.shadowing = getSkinParam().shadowing(getEntity().getStereotype()) ? 3 : 0; this.stroke = GeneralImageBuilder.getForcedStroke(getEntity().getStereotype(), getSkinParam()); this.roundCorner = 0; this.back = Cluster.getBackColor(specificBackColor, skinParam, stereotype, styleName); + titleFontConfiguration = new FontConfiguration(getSkinParam(), FontParam.PACKAGE, stereotype); + titleHorizontalAlignment = HorizontalAlignment.CENTER; } + this.desc = entity.getDisplay().create(titleFontConfiguration, titleHorizontalAlignment, skinParam); + final DisplayPositionned legend = ((EntityImpl) entity).getLegend(); if (legend != null) { final TextBlock legendBlock = EntityImageLegend.create(legend.getDisplay(), skinParam); @@ -136,7 +145,7 @@ public class EntityImageEmptyPackage extends AbstractEntityImage { } else { stereoBlock = TextBlockUtils.withMargin(Display.create(stereotype.getLabels(skinParam.guillemet())) .create(new FontConfiguration(getSkinParam(), FontParam.PACKAGE_STEREOTYPE, stereotype), - HorizontalAlignment.CENTER, skinParam), + titleHorizontalAlignment, skinParam), 1, 0); } } diff --git a/src/net/sourceforge/plantuml/svek/image/EntityImageLollipopInterface.java b/src/net/sourceforge/plantuml/svek/image/EntityImageLollipopInterface.java index 1a4b6ed1f..746a3ee66 100644 --- a/src/net/sourceforge/plantuml/svek/image/EntityImageLollipopInterface.java +++ b/src/net/sourceforge/plantuml/svek/image/EntityImageLollipopInterface.java @@ -54,9 +54,9 @@ import net.sourceforge.plantuml.svek.AbstractEntityImage; import net.sourceforge.plantuml.svek.ShapeType; import net.sourceforge.plantuml.ugraphic.UEllipse; import net.sourceforge.plantuml.ugraphic.UGraphic; +import net.sourceforge.plantuml.ugraphic.UGroupType; import net.sourceforge.plantuml.ugraphic.UStroke; import net.sourceforge.plantuml.ugraphic.UTranslate; -import net.sourceforge.plantuml.ugraphic.UGroupType; public class EntityImageLollipopInterface extends AbstractEntityImage { diff --git a/src/net/sourceforge/plantuml/svek/image/EntityImageMap.java b/src/net/sourceforge/plantuml/svek/image/EntityImageMap.java index a6b45e88f..1dc773cac 100644 --- a/src/net/sourceforge/plantuml/svek/image/EntityImageMap.java +++ b/src/net/sourceforge/plantuml/svek/image/EntityImageMap.java @@ -69,11 +69,11 @@ import net.sourceforge.plantuml.ugraphic.PlacementStrategyY1Y2; import net.sourceforge.plantuml.ugraphic.Shadowable; import net.sourceforge.plantuml.ugraphic.UGraphic; import net.sourceforge.plantuml.ugraphic.UGraphicStencil; +import net.sourceforge.plantuml.ugraphic.UGroupType; import net.sourceforge.plantuml.ugraphic.ULayoutGroup; import net.sourceforge.plantuml.ugraphic.URectangle; import net.sourceforge.plantuml.ugraphic.UStroke; import net.sourceforge.plantuml.ugraphic.UTranslate; -import net.sourceforge.plantuml.ugraphic.UGroupType; import net.sourceforge.plantuml.ugraphic.color.HColor; public class EntityImageMap extends AbstractEntityImage implements Stencil, WithPorts { diff --git a/src/net/sourceforge/plantuml/svek/image/EntityImageObject.java b/src/net/sourceforge/plantuml/svek/image/EntityImageObject.java index e0bd2da3c..08090ef63 100644 --- a/src/net/sourceforge/plantuml/svek/image/EntityImageObject.java +++ b/src/net/sourceforge/plantuml/svek/image/EntityImageObject.java @@ -67,12 +67,12 @@ import net.sourceforge.plantuml.ugraphic.PlacementStrategyY1Y2; import net.sourceforge.plantuml.ugraphic.Shadowable; import net.sourceforge.plantuml.ugraphic.UGraphic; import net.sourceforge.plantuml.ugraphic.UGraphicStencil; +import net.sourceforge.plantuml.ugraphic.UGroupType; import net.sourceforge.plantuml.ugraphic.ULayoutGroup; import net.sourceforge.plantuml.ugraphic.URectangle; import net.sourceforge.plantuml.ugraphic.UStroke; import net.sourceforge.plantuml.ugraphic.UTranslate; import net.sourceforge.plantuml.ugraphic.color.HColor; -import net.sourceforge.plantuml.ugraphic.UGroupType; public class EntityImageObject extends AbstractEntityImage implements Stencil { diff --git a/src/net/sourceforge/plantuml/svek/image/EntityImagePort.java b/src/net/sourceforge/plantuml/svek/image/EntityImagePort.java index 1c0003dfe..8467bfde7 100644 --- a/src/net/sourceforge/plantuml/svek/image/EntityImagePort.java +++ b/src/net/sourceforge/plantuml/svek/image/EntityImagePort.java @@ -50,8 +50,8 @@ import net.sourceforge.plantuml.graphic.StringBounder; import net.sourceforge.plantuml.graphic.color.ColorType; import net.sourceforge.plantuml.svek.Bibliotekon; import net.sourceforge.plantuml.svek.Cluster; -import net.sourceforge.plantuml.svek.SvekNode; import net.sourceforge.plantuml.svek.ShapeType; +import net.sourceforge.plantuml.svek.SvekNode; import net.sourceforge.plantuml.ugraphic.Shadowable; import net.sourceforge.plantuml.ugraphic.UGraphic; import net.sourceforge.plantuml.ugraphic.URectangle; diff --git a/src/net/sourceforge/plantuml/svek/image/EntityImageTips.java b/src/net/sourceforge/plantuml/svek/image/EntityImageTips.java index d627ec108..33680f0a9 100644 --- a/src/net/sourceforge/plantuml/svek/image/EntityImageTips.java +++ b/src/net/sourceforge/plantuml/svek/image/EntityImageTips.java @@ -60,8 +60,8 @@ import net.sourceforge.plantuml.graphic.color.ColorType; import net.sourceforge.plantuml.skin.rose.Rose; import net.sourceforge.plantuml.svek.AbstractEntityImage; import net.sourceforge.plantuml.svek.Bibliotekon; -import net.sourceforge.plantuml.svek.SvekNode; import net.sourceforge.plantuml.svek.ShapeType; +import net.sourceforge.plantuml.svek.SvekNode; import net.sourceforge.plantuml.ugraphic.UGraphic; import net.sourceforge.plantuml.ugraphic.UTranslate; import net.sourceforge.plantuml.ugraphic.color.HColor; diff --git a/src/net/sourceforge/plantuml/ugraphic/eps/DriverTextEps.java b/src/net/sourceforge/plantuml/ugraphic/eps/DriverTextEps.java index 7ee515c45..7b7c2200f 100644 --- a/src/net/sourceforge/plantuml/ugraphic/eps/DriverTextEps.java +++ b/src/net/sourceforge/plantuml/ugraphic/eps/DriverTextEps.java @@ -164,7 +164,8 @@ public class DriverTextEps implements UDriver { private void drawAsText(UText shape, double x, double y, UParam param, EpsGraphics eps, ColorMapper mapper) { final FontConfiguration fontConfiguration = shape.getFontConfiguration(); - // final FontMetrics fm = g2dummy.getFontMetrics(fontConfiguration.getFont().getFont()); + // final FontMetrics fm = + // g2dummy.getFontMetrics(fontConfiguration.getFont().getFont()); // final double ypos = y - fm.getDescent() + 0.5; final double ypos = y - 1; diff --git a/src/net/sourceforge/plantuml/utils/MTRandom.java b/src/net/sourceforge/plantuml/utils/MTRandom.java new file mode 100644 index 000000000..f58740795 --- /dev/null +++ b/src/net/sourceforge/plantuml/utils/MTRandom.java @@ -0,0 +1,390 @@ +/* + * MTRandom : A Java implementation of the MT19937 (Mersenne Twister) + * pseudo random number generator algorithm based upon the + * original C code by Makoto Matsumoto and Takuji Nishimura. + * Author : David Beaumont + * Email : mersenne-at-www.goui.net + * + * For the original C code, see: + * http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html + * + * This version, Copyright (C) 2005, David Beaumont. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +package net.sourceforge.plantuml.utils; + +import java.util.Random; + +/** + * @version 1.0 + * @author David Beaumont, Copyright 2005 + *

+ * A Java implementation of the MT19937 (Mersenne Twister) pseudo + * random number generator algorithm based upon the original C code + * by Makoto Matsumoto and Takuji Nishimura (see + * + * http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html for + * more information. + *

+ * As a subclass of java.util.Random this class provides a single + * canonical method next() for generating bits in the pseudo random + * number sequence. Anyone using this class should invoke the public + * inherited methods (nextInt(), nextFloat etc.) to obtain values as + * normal. This class should provide a drop-in replacement for the + * standard implementation of java.util.Random with the additional + * advantage of having a far longer period and the ability to use a + * far larger seed value. + *

+ * This is not a cryptographically strong source of randomness + * and should not be used for cryptographic systems or in any + * other situation where true random numbers are required. + *

+ * + * CC-GNU LGPL
+ * This software is licensed under the CC-GNU LGPL. + * + * + * + * + */ +public class MTRandom extends Random { + + /** + * Auto-generated serial version UID. Note that MTRandom does NOT + * support serialisation of its internal state and it may even be + * necessary to implement read/write methods to re-seed it properly. + * This is only here to make Eclipse shut up about it being missing. + */ + private static final long serialVersionUID = -515082678588212038L; + + // Constants used in the original C implementation + private final static int UPPER_MASK = 0x80000000; + private final static int LOWER_MASK = 0x7fffffff; + + private final static int N = 624; + private final static int M = 397; + private final static int MAGIC[] = { 0x0, 0x9908b0df }; + private final static int MAGIC_FACTOR1 = 1812433253; + private final static int MAGIC_FACTOR2 = 1664525; + private final static int MAGIC_FACTOR3 = 1566083941; + private final static int MAGIC_MASK1 = 0x9d2c5680; + private final static int MAGIC_MASK2 = 0xefc60000; + private final static int MAGIC_SEED = 19650218; + private final static long DEFAULT_SEED = 5489L; + + // Internal state + private transient int[] mt; + private transient int mti; + private transient boolean compat = false; + + // Temporary buffer used during setSeed(long) + private transient int[] ibuf; + + /** + * The default constructor for an instance of MTRandom. This invokes + * the no-argument constructor for java.util.Random which will result + * in the class being initialised with a seed value obtained by calling + * System.currentTimeMillis(). + */ + public MTRandom() { } + + /** + * This version of the constructor can be used to implement identical + * behaviour to the original C code version of this algorithm including + * exactly replicating the case where the seed value had not been set + * prior to calling genrand_int32. + *

+ * If the compatibility flag is set to true, then the algorithm will be + * seeded with the same default value as was used in the original C + * code. Furthermore the setSeed() method, which must take a 64 bit + * long value, will be limited to using only the lower 32 bits of the + * seed to facilitate seamless migration of existing C code into Java + * where identical behaviour is required. + *

+ * Whilst useful for ensuring backwards compatibility, it is advised + * that this feature not be used unless specifically required, due to + * the reduction in strength of the seed value. + * + * @param compatible Compatibility flag for replicating original + * behaviour. + */ + public MTRandom(boolean compatible) { + super(0L); + compat = compatible; + setSeed(compat?DEFAULT_SEED:System.currentTimeMillis()); + } + + /** + * This version of the constructor simply initialises the class with + * the given 64 bit seed value. For a better random number sequence + * this seed value should contain as much entropy as possible. + * + * @param seed The seed value with which to initialise this class. + */ + public MTRandom(long seed) { + super(seed); + } + + /** + * This version of the constructor initialises the class with the + * given byte array. All the data will be used to initialise this + * instance. + * + * @param buf The non-empty byte array of seed information. + * @throws NullPointerException if the buffer is null. + * @throws IllegalArgumentException if the buffer has zero length. + */ + public MTRandom(byte[] buf) { + super(0L); + setSeed(buf); + } + + /** + * This version of the constructor initialises the class with the + * given integer array. All the data will be used to initialise + * this instance. + * + * @param buf The non-empty integer array of seed information. + * @throws NullPointerException if the buffer is null. + * @throws IllegalArgumentException if the buffer has zero length. + */ + public MTRandom(int[] buf) { + super(0L); + setSeed(buf); + } + + // Initializes mt[N] with a simple integer seed. This method is + // required as part of the Mersenne Twister algorithm but need + // not be made public. + private final void setSeed(int seed) { + + // Annoying runtime check for initialisation of internal data + // caused by java.util.Random invoking setSeed() during init. + // This is unavoidable because no fields in our instance will + // have been initialised at this point, not even if the code + // were placed at the declaration of the member variable. + if (mt == null) mt = new int[N]; + + // ---- Begin Mersenne Twister Algorithm ---- + mt[0] = seed; + for (mti = 1; mti < N; mti++) { + mt[mti] = (MAGIC_FACTOR1 * (mt[mti-1] ^ (mt[mti-1] >>> 30)) + mti); + } + // ---- End Mersenne Twister Algorithm ---- + } + + /** + * This method resets the state of this instance using the 64 + * bits of seed data provided. Note that if the same seed data + * is passed to two different instances of MTRandom (both of + * which share the same compatibility state) then the sequence + * of numbers generated by both instances will be identical. + *

+ * If this instance was initialised in 'compatibility' mode then + * this method will only use the lower 32 bits of any seed value + * passed in and will match the behaviour of the original C code + * exactly with respect to state initialisation. + * + * @param seed The 64 bit value used to initialise the random + * number generator state. + */ + public final synchronized void setSeed(long seed) { + if (compat) { + setSeed((int)seed); + } else { + + // Annoying runtime check for initialisation of internal data + // caused by java.util.Random invoking setSeed() during init. + // This is unavoidable because no fields in our instance will + // have been initialised at this point, not even if the code + // were placed at the declaration of the member variable. + if (ibuf == null) ibuf = new int[2]; + + ibuf[0] = (int)seed; + ibuf[1] = (int)(seed >>> 32); + setSeed(ibuf); + } + } + + /** + * This method resets the state of this instance using the byte + * array of seed data provided. Note that calling this method + * is equivalent to calling "setSeed(pack(buf))" and in particular + * will result in a new integer array being generated during the + * call. If you wish to retain this seed data to allow the pseudo + * random sequence to be restarted then it would be more efficient + * to use the "pack()" method to convert it into an integer array + * first and then use that to re-seed the instance. The behaviour + * of the class will be the same in both cases but it will be more + * efficient. + * + * @param buf The non-empty byte array of seed information. + * @throws NullPointerException if the buffer is null. + * @throws IllegalArgumentException if the buffer has zero length. + */ + public final void setSeed(byte[] buf) { + setSeed(pack(buf)); + } + + /** + * This method resets the state of this instance using the integer + * array of seed data provided. This is the canonical way of + * resetting the pseudo random number sequence. + * + * @param buf The non-empty integer array of seed information. + * @throws NullPointerException if the buffer is null. + * @throws IllegalArgumentException if the buffer has zero length. + */ + public final synchronized void setSeed(int[] buf) { + int length = buf.length; + if (length == 0) throw new IllegalArgumentException("Seed buffer may not be empty"); + // ---- Begin Mersenne Twister Algorithm ---- + int i = 1, j = 0, k = (N > length ? N : length); + setSeed(MAGIC_SEED); + for (; k > 0; k--) { + mt[i] = (mt[i] ^ ((mt[i-1] ^ (mt[i-1] >>> 30)) * MAGIC_FACTOR2)) + buf[j] + j; + i++; j++; + if (i >= N) { mt[0] = mt[N-1]; i = 1; } + if (j >= length) j = 0; + } + for (k = N-1; k > 0; k--) { + mt[i] = (mt[i] ^ ((mt[i-1] ^ (mt[i-1] >>> 30)) * MAGIC_FACTOR3)) - i; + i++; + if (i >= N) { mt[0] = mt[N-1]; i = 1; } + } + mt[0] = UPPER_MASK; // MSB is 1; assuring non-zero initial array + // ---- End Mersenne Twister Algorithm ---- + } + + /** + * This method forms the basis for generating a pseudo random number + * sequence from this class. If given a value of 32, this method + * behaves identically to the genrand_int32 function in the original + * C code and ensures that using the standard nextInt() function + * (inherited from Random) we are able to replicate behaviour exactly. + *

+ * Note that where the number of bits requested is not equal to 32 + * then bits will simply be masked out from the top of the returned + * integer value. That is to say that: + *

+	 * mt.setSeed(12345);
+	 * int foo = mt.nextInt(16) + (mt.nextInt(16) << 16);
+ * will not give the same result as + *
+	 * mt.setSeed(12345);
+	 * int foo = mt.nextInt(32);
+ * + * @param bits The number of significant bits desired in the output. + * @return The next value in the pseudo random sequence with the + * specified number of bits in the lower part of the integer. + */ + protected final synchronized int next(int bits) { + // ---- Begin Mersenne Twister Algorithm ---- + int y, kk; + if (mti >= N) { // generate N words at one time + + // In the original C implementation, mti is checked here + // to determine if initialisation has occurred; if not + // it initialises this instance with DEFAULT_SEED (5489). + // This is no longer necessary as initialisation of the + // Java instance must result in initialisation occurring + // Use the constructor MTRandom(true) to enable backwards + // compatible behaviour. + + for (kk = 0; kk < N-M; kk++) { + y = (mt[kk] & UPPER_MASK) | (mt[kk+1] & LOWER_MASK); + mt[kk] = mt[kk+M] ^ (y >>> 1) ^ MAGIC[y & 0x1]; + } + for (;kk < N-1; kk++) { + y = (mt[kk] & UPPER_MASK) | (mt[kk+1] & LOWER_MASK); + mt[kk] = mt[kk+(M-N)] ^ (y >>> 1) ^ MAGIC[y & 0x1]; + } + y = (mt[N-1] & UPPER_MASK) | (mt[0] & LOWER_MASK); + mt[N-1] = mt[M-1] ^ (y >>> 1) ^ MAGIC[y & 0x1]; + + mti = 0; + } + + y = mt[mti++]; + + // Tempering + y ^= (y >>> 11); + y ^= (y << 7) & MAGIC_MASK1; + y ^= (y << 15) & MAGIC_MASK2; + y ^= (y >>> 18); + // ---- End Mersenne Twister Algorithm ---- + return (y >>> (32-bits)); + } + + // This is a fairly obscure little code section to pack a + // byte[] into an int[] in little endian ordering. + + /** + * This simply utility method can be used in cases where a byte + * array of seed data is to be used to repeatedly re-seed the + * random number sequence. By packing the byte array into an + * integer array first, using this method, and then invoking + * setSeed() with that; it removes the need to re-pack the byte + * array each time setSeed() is called. + *

+ * If the length of the byte array is not a multiple of 4 then + * it is implicitly padded with zeros as necessary. For example: + *

    byte[] { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06 }
+ * becomes + *
    int[]  { 0x04030201, 0x00000605 }
+ *

+ * Note that this method will not complain if the given byte array + * is empty and will produce an empty integer array, but the + * setSeed() method will throw an exception if the empty integer + * array is passed to it. + * + * @param buf The non-null byte array to be packed. + * @return A non-null integer array of the packed bytes. + * @throws NullPointerException if the given byte array is null. + */ + public static int[] pack(byte[] buf) { + int k, blen = buf.length, ilen = ((buf.length+3) >>> 2); + int[] ibuf = new int[ilen]; + for (int n = 0; n < ilen; n++) { + int m = (n+1) << 2; + if (m > blen) m = blen; + for (k = buf[--m]&0xff; (m & 0x3) != 0; k = (k << 8) | buf[--m]&0xff); + ibuf[n] = k; + } + return ibuf; + } +} \ No newline at end of file diff --git a/src/net/sourceforge/plantuml/version/Version.java b/src/net/sourceforge/plantuml/version/Version.java index 05fc9a50c..4ed3e7330 100644 --- a/src/net/sourceforge/plantuml/version/Version.java +++ b/src/net/sourceforge/plantuml/version/Version.java @@ -80,7 +80,7 @@ public class Version { } public static int beta() { - final int beta = 3; + final int beta = 4; return beta; }