/* * SVG Salamander * Copyright (c) 2004, Mark McKay * All rights reserved. * * Redistribution and use in source and binary forms, with or * without modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above * copyright notice, this list of conditions and the following * disclaimer. * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. * * Mark McKay can be contacted at mark@kitfox.com. Salamander and other * projects can be found at http://www.kitfox.com * * Created on February 18, 2004, 1:49 PM */ package com.kitfox.svg.xml; import java.awt.Toolkit; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedList; import java.util.logging.Level; import java.util.logging.Logger; import java.util.regex.Matcher; import java.util.regex.Pattern; import com.kitfox.svg.SVGConst; /** * @author Mark McKay * @author <a href="mailto:mark@kitfox.com">Mark McKay</a> */ public class XMLParseUtil { static final Matcher fpMatch = Pattern.compile("([-+]?((\\d*\\.\\d+)|(\\d+))([eE][+-]?\\d+)?)(\\%|in|cm|mm|pt|pc|px|em|ex)?").matcher(""); static final Matcher intMatch = Pattern.compile("[-+]?\\d+").matcher(""); /** Creates a new instance of XMLParseUtil */ private XMLParseUtil() { } public static String[] parseStringList(String list) { final Matcher matchWs = Pattern.compile("[^\\s]+").matcher(""); matchWs.reset(list); LinkedList<String> matchList = new LinkedList<>(); while (matchWs.find()) { matchList.add(matchWs.group()); } String[] retArr = new String[matchList.size()]; return matchList.toArray(retArr); } public static double parseDouble(String val) { return findDouble(val); } /** * Searches the given string for the first floating point number it contains, * parses and returns it. */ public synchronized static double findDouble(String val) { if (val == null) return 0; fpMatch.reset(val); try { if (!fpMatch.find()) return 0; } catch (StringIndexOutOfBoundsException e) { Logger.getLogger(SVGConst.SVG_LOGGER).log(Level.WARNING, "XMLParseUtil: regex parse problem: '" + val + "'", e); } val = fpMatch.group(1); //System.err.println("Parsing " + val); double retVal = 0; try { retVal = Double.parseDouble(val); float pixPerInch; try { pixPerInch = Toolkit.getDefaultToolkit().getScreenResolution(); } catch (NoClassDefFoundError err) { //Default value for headless X servers pixPerInch = 72; } final float inchesPerCm = .3936f; final String units = fpMatch.group(6); if ("%".equals(units)) retVal /= 100; else if ("in".equals(units)) { retVal *= pixPerInch; } else if ("cm".equals(units)) { retVal *= inchesPerCm * pixPerInch; } else if ("mm".equals(units)) { retVal *= inchesPerCm * pixPerInch * .1f; } else if ("pt".equals(units)) { retVal *= (1f / 72f) * pixPerInch; } else if ("pc".equals(units)) { retVal *= (1f / 6f) * pixPerInch; } } catch (Exception e) {} return retVal; } /** * Scans an input string for double values. For each value found, places * in a list. This method regards any characters not part of a floating * point value to be seperators. Thus this will parse whitespace seperated, * comma seperated, and many other separation schemes correctly. */ public synchronized static double[] parseDoubleList(String list) { if (list == null) return null; fpMatch.reset(list); LinkedList<Double> doubList = new LinkedList<>(); while (fpMatch.find()) { String val = fpMatch.group(1); doubList.add(Double.valueOf(val)); } double[] retArr = new double[doubList.size()]; Iterator<Double> it = doubList.iterator(); int idx = 0; while (it.hasNext()) { retArr[idx++] = it.next().doubleValue(); } return retArr; } /** * Searches the given string for the first floating point number it contains, * parses and returns it. */ public synchronized static float findFloat(String val) { if (val == null) return 0f; fpMatch.reset(val); if (!fpMatch.find()) return 0f; val = fpMatch.group(1); //System.err.println("Parsing " + val); float retVal = 0f; try { retVal = Float.parseFloat(val); String units = fpMatch.group(6); if ("%".equals(units)) retVal /= 100; } catch (Exception e) {} return retVal; } public synchronized static float[] parseFloatList(String list) { if (list == null) return null; fpMatch.reset(list); LinkedList<Float> floatList = new LinkedList<>(); while (fpMatch.find()) { String val = fpMatch.group(1); floatList.add(Float.valueOf(val)); } float[] retArr = new float[floatList.size()]; Iterator<Float> it = floatList.iterator(); int idx = 0; while (it.hasNext()) { retArr[idx++] = it.next().floatValue(); } return retArr; } /** * Searches the given string for the first integer point number it contains, * parses and returns it. */ public static int findInt(String val) { if (val == null) return 0; intMatch.reset(val); if (!intMatch.find()) return 0; val = intMatch.group(); int retVal = 0; try { retVal = Integer.parseInt(val); } catch (Exception e) {} return retVal; } public static int[] parseIntList(String list) { if (list == null) return null; intMatch.reset(list); LinkedList<Integer> intList = new LinkedList<>(); while (intMatch.find()) { String val = intMatch.group(); intList.add(Integer.valueOf(val)); } int[] retArr = new int[intList.size()]; Iterator<Integer> it = intList.iterator(); int idx = 0; while (it.hasNext()) { retArr[idx++] = it.next().intValue(); } return retArr; } /** * The input string represents a ratio. Can either be specified as a * double number on the range of [0.0 1.0] or as a percentage [0% 100%] */ public static double parseRatio(String val) { if (val == null || val.equals("")) return 0.0; if (val.charAt(val.length() - 1) == '%') { parseDouble(val.substring(0, val.length() - 1)); } return parseDouble(val); } public static NumberWithUnits parseNumberWithUnits(String val) { if (val == null) return null; return new NumberWithUnits(val); } /** * Takes a CSS style string and returns a hash of them. * @param styleString - A CSS formatted string of styles. Eg, * "font-size:12;fill:#d32c27;fill-rule:evenodd;stroke-width:1pt;" * @param map - A map to which these styles will be added */ public static HashMap<String, StyleAttribute> parseStyle(String styleString, HashMap<String, StyleAttribute> map) { final Pattern patSemi = Pattern.compile(";"); String[] styles = patSemi.split(styleString); for (int i = 0; i < styles.length; i++) { if (styles[i].length() == 0) { continue; } int colon = styles[i].indexOf(':'); if (colon == -1) { continue; } String key = styles[i].substring(0, colon).trim(); String value = styles[i].substring(colon + 1).trim(); map.put(key, new StyleAttribute(key, value)); } return map; } }