/* ======================================================================== * PlantUML : a free UML diagram generator * ======================================================================== * * (C) Copyright 2009-2023, 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.style; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.EnumMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import net.sourceforge.plantuml.FileSystem; import net.sourceforge.plantuml.LineLocationImpl; import net.sourceforge.plantuml.Log; import net.sourceforge.plantuml.SkinParam; import net.sourceforge.plantuml.StringLocated; import net.sourceforge.plantuml.command.BlocLines; import net.sourceforge.plantuml.command.regex.Matcher2; import net.sourceforge.plantuml.command.regex.MyPattern; import net.sourceforge.plantuml.command.regex.Pattern2; import net.sourceforge.plantuml.security.SFile; public class StyleLoader { public static final int DELTA_PRIORITY_FOR_STEREOTYPE = 1000; private final SkinParam skinParam; public StyleLoader(SkinParam skinParam) { this.skinParam = skinParam; } private StyleBuilder styleBuilder; public StyleBuilder loadSkin(String filename) throws IOException { this.styleBuilder = new StyleBuilder(skinParam); final InputStream internalIs = getInputStreamForStyle(filename); if (internalIs == null) { Log.error("No .skin file seems to be available"); throw new NoStyleAvailableException(); } final BlocLines lines2 = BlocLines.load(internalIs, new LineLocationImpl(filename, null)); loadSkinInternal(lines2); if (this.styleBuilder == null) { Log.error("No .skin file seems to be available"); throw new NoStyleAvailableException(); } return this.styleBuilder; } public static InputStream getInputStreamForStyle(String filename) throws IOException { InputStream internalIs = null; SFile localFile = new SFile(filename); Log.info("Trying to load style " + filename); try { if (localFile.exists() == false) localFile = FileSystem.getInstance().getFile(filename); } catch (IOException e) { Log.info("Cannot open file. " + e); } if (localFile.exists()) { Log.info("File found : " + localFile.getPrintablePath()); internalIs = localFile.openFile(); } else { Log.info("File not found : " + localFile.getPrintablePath()); final String res = "/skin/" + filename; internalIs = StyleLoader.class.getResourceAsStream(res); if (internalIs != null) Log.info("... but " + filename + " found inside the .jar"); } return internalIs; } private void loadSkinInternal(final BlocLines lines) { for (Style newStyle : getDeclaredStyles(lines, styleBuilder)) this.styleBuilder.loadInternal(newStyle.getSignature(), newStyle); } private final static String KEYNAMES = "[-.\\w(), ]+?"; private final static Pattern2 keyName = MyPattern.cmpile("^[:]?(" + KEYNAMES + ")([%s]+\\*)?[%s]*\\{$"); private final static Pattern2 propertyAndValue = MyPattern.cmpile("^([\\w]+):?[%s]+(.*?);?$"); private final static Pattern2 closeBracket = MyPattern.cmpile("^\\}$"); public static Collection