CssSyntaxUtils.java
/*
* SmartSprites Project
*
* Copyright (C) 2007-2009, Stanisław Osiński.
* 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.
*
* - Neither the name of the SmartSprites Project nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* - We kindly request that you include in the end-user documentation provided with
* the redistribution and/or in the software itself an acknowledgement equivalent
* to the following: "This product includes software developed by the SmartSprites
* Project."
*
* 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 OWNER 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.
*/
package org.carrot2.labs.smartsprites.css;
import java.awt.Color;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.carrot2.labs.smartsprites.message.Message;
import org.carrot2.labs.smartsprites.message.Message.MessageType;
import org.carrot2.labs.smartsprites.message.MessageLog;
import org.carrot2.util.StringUtils;
/**
* A few utility methods for processing CSS syntax.
*/
public class CssSyntaxUtils {
/** The Constant URL_PATTERN. */
private static final Pattern URL_PATTERN = Pattern.compile("[uU][rR][lL]\\((['\"]?)([^'\"]*)\\1\\)");
/** The Constant COLOR_PATTERN. */
private static final Pattern COLOR_PATTERN = Pattern.compile("#([0-9a-f]{6})");
/** The Constant IMPORTANT_PATTERN. */
private static final Pattern IMPORTANT_PATTERN = Pattern.compile("!\\s*important");
/**
* Instantiates a new css syntax utils.
*/
private CssSyntaxUtils() {
// Prevent Instantiation
}
/**
* Extracts CSS properties from the provided {@link String}.
*
* @param text
* the text
*
* @return the list
*/
public static List<CssProperty> extractProperties(String text) {
return extractRules(text, null);
}
/**
* Extracts CSS properties from the provided {@link String} and logs warnings to the provided {@link MessageLog}.
*
* @param text
* the text
* @param messageLog
* the message log
*
* @return the list
*/
public static List<CssProperty> extractRules(String text, MessageLog messageLog) {
final List<CssProperty> rules = new ArrayList<>();
final String[] chunks = text.split(";");
for (final String chunk : chunks) {
final String[] parts = chunk.split(":", 2);
if (parts.length == 2) {
String value = parts[1].trim();
final Matcher matcher = IMPORTANT_PATTERN.matcher(value);
boolean important = false;
if (matcher.find()) {
important = true;
value = matcher.replaceAll("");
}
rules.add(new CssProperty(parts[0].trim().toLowerCase(Locale.ENGLISH), value.trim(), important));
} else if (messageLog != null) {
messageLog.warning(Message.MessageType.MALFORMED_CSS_RULE, chunk.trim());
}
}
return rules;
}
/**
* Converts the provided collection of CSS properties to a {@link Map} with keys being property names and values
* being {@link CssProperty} objects.
*
* @param rules
* the rules
*
* @return the map
*/
public static Map<String, CssProperty> propertiesAsMap(Collection<CssProperty> rules) {
final Map<String, CssProperty> result = new LinkedHashMap<>();
for (final CssProperty cssProperty : rules) {
result.put(cssProperty.rule, cssProperty);
}
return result;
}
/**
* Returns the value of a CSS property if it exists, <code>null</code> otherwise.
*
* @param rules
* the rules
* @param property
* the property
*
* @return the value
*/
public static String getValue(Map<String, CssProperty> rules, String property) {
final CssProperty cssProperty = rules.get(property);
if (cssProperty != null) {
return cssProperty.value;
}
return null;
}
/**
* Returns <code>true</code> if the the provided map contains a property with the specified name that has a
* non-blank value.
*
* @param properties
* the properties
* @param propertyName
* the property name
*
* @return true, if successful
*/
public static boolean hasNonBlankValue(Map<String, CssProperty> properties, String propertyName) {
return properties.containsKey(propertyName) && StringUtils.isNotBlank(properties.get(propertyName).value);
}
/**
* Extracts the actual url from the CSS url expression like <code>url('actua_url')</code>.
*
* @param urlValue
* the url value
*
* @return the string
*/
public static String unpackUrl(String urlValue) {
return unpackUrl(urlValue, null);
}
/**
* Extracts the actual url from the CSS url expression like <code>url('actua_url')</code> and logs warnings to the
* provided {@link MessageLog}.
*
* @param urlValue
* the url value
* @param messageLog
* the message log
*
* @return the string
*/
public static String unpackUrl(String urlValue, MessageLog messageLog) {
final Matcher matcher = URL_PATTERN.matcher(urlValue);
if (!matcher.matches()) {
if (messageLog != null) {
messageLog.warning(MessageType.MALFORMED_URL, urlValue);
}
return null;
}
final String url = matcher.group(2);
return url != null ? url.trim() : url;
}
/**
* Parses a hexadecimal format (#fff or #ffffff) of CSS color into a {@link Color} object. The RGB format (rgb(100,
* 0, 0)) is currently not supported. In case of parse errors, the default is returned
*
* @param colorValue
* the color value
* @param messageLog
* the message log
* @param defaultColor
* the default color
*
* @return the color
*/
public static Color parseColor(String colorValue, MessageLog messageLog, Color defaultColor) {
final Matcher matcher = COLOR_PATTERN.matcher(colorValue);
if (!matcher.matches()) {
if (messageLog != null) {
messageLog.warning(MessageType.MALFORMED_COLOR, colorValue);
}
return defaultColor;
}
return new Color(Integer.parseInt(matcher.group(1), 16));
}
}