/*******************************************************************************
* Copyright (c) 2004, 2006
* Thomas Hallgren, Kenneth Olwing, Mitch Sonies
* Pontus Rydin, Nils Unden, Peer Torngren
* The code, documentation and other materials contained herein have been
* licensed under the Eclipse Public License - v 1.0 by the individual
* copyright holders listed above, as Initial Contributors under such license.
* The text of such license is available at www.eclipse.org.
*******************************************************************************/
package org.eclipse.buckminster.core.helpers;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import org.eclipse.buckminster.core.Messages;
import org.eclipse.buckminster.core.common.model.IProperties;
public class BMProperties implements IProperties<String> {
private static final IProperties<String> systemProperties = new PropertiesWrapper() {
@Override
protected Properties getProperties() {
return System.getProperties();
}
};
/** A table of hex digits */
private static final char[] hexDigit = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
public static IProperties<String> getSystemProperties() {
return systemProperties;
}
public static void store(Map<String, ? extends Object> props, OutputStream out, String comments) throws IOException {
BufferedWriter awriter;
awriter = new BufferedWriter(new OutputStreamWriter(out, "8859_1")); //$NON-NLS-1$
if (comments != null)
writeln(awriter, "#" + comments); //$NON-NLS-1$
writeln(awriter, "#" + new Date().toString()); //$NON-NLS-1$
synchronized (props) {
for (Entry<String, ? extends Object> e : props.entrySet()) {
String key = e.getKey();
key = saveConvert(key, true);
/*
* No need to escape embedded and trailing spaces for value,
* hence pass false to flag.
*/
writeln(awriter, key + "=" + saveConvert(e.getValue(), false)); //$NON-NLS-1$
}
}
awriter.flush();
}
private static String saveConvert(Object value, boolean escapeSpace) {
String theString = value.toString();
int len = theString.length();
int bufLen = len * 2;
if (bufLen < 0) {
bufLen = Integer.MAX_VALUE;
}
StringBuffer outBuffer = new StringBuffer(bufLen);
for (int x = 0; x < len; x++) {
char aChar = theString.charAt(x);
// Handle common case first, selecting largest block that
// avoids the specials below
if ((aChar > 61) && (aChar < 127)) {
if (aChar == '\\') {
outBuffer.append('\\');
outBuffer.append('\\');
continue;
}
outBuffer.append(aChar);
continue;
}
switch (aChar) {
case ' ':
if (x == 0 || escapeSpace)
outBuffer.append('\\');
outBuffer.append(' ');
break;
case '\t':
outBuffer.append('\\');
outBuffer.append('t');
break;
case '\n':
outBuffer.append('\\');
outBuffer.append('n');
break;
case '\r':
outBuffer.append('\\');
outBuffer.append('r');
break;
case '\f':
outBuffer.append('\\');
outBuffer.append('f');
break;
case '=': // Fall through
case '#': // Fall through
case '!':
outBuffer.append('\\');
outBuffer.append(aChar);
break;
default:
if ((aChar < 0x0020) || (aChar > 0x007e)) {
outBuffer.append('\\');
outBuffer.append('u');
outBuffer.append(toHex((aChar >> 12) & 0xF));
outBuffer.append(toHex((aChar >> 8) & 0xF));
outBuffer.append(toHex((aChar >> 4) & 0xF));
outBuffer.append(toHex(aChar & 0xF));
} else {
outBuffer.append(aChar);
}
}
}
return outBuffer.toString();
}
/**
* Convert a nibble to a hex character
*
* @param nibble
* the nibble to convert.
*/
private static char toHex(int nibble) {
return hexDigit[(nibble & 0xF)];
}
private static void writeln(BufferedWriter bw, String s) throws IOException {
bw.write(s);
bw.newLine();
}
private final Map<String, String> map;
public BMProperties() {
map = new HashMap<String, String>();
}
public BMProperties(InputStream inStream) throws IOException {
final Properties loader = new Properties();
loader.load(inStream);
map = new PropertiesWrapper() {
@Override
protected Properties getProperties() {
return loader;
}
};
}
public BMProperties(Map<String, String> defaultProps) {
Map<String, String> props = new HashMap<String, String>();
if (defaultProps != null)
props = new MapUnion<String, String>(props, defaultProps);
map = props;
}
public BMProperties(Map<String, String> mutableProps, Map<String, String> defaultProps) {
if (defaultProps != null)
mutableProps = new MapUnion<String, String>(mutableProps, defaultProps);
map = mutableProps;
}
public BMProperties(final Properties defaultProps) {
map = new PropertiesWrapper() {
@Override
protected Properties getProperties() {
return defaultProps;
}
};
}
@Override
public void clear() {
map.clear();
}
@Override
public boolean containsKey(Object key) {
return map.containsKey(key);
}
@Override
public boolean containsValue(Object value) {
return map.containsValue(value);
}
@Override
public Set<Entry<String, String>> entrySet() {
return map.entrySet();
}
@Override
public boolean equals(Object o) {
return this == o || (o instanceof Map<?, ?> && o.equals(map));
}
@Override
public String get(Object key) {
return map.get(key);
}
@Override
public int hashCode() {
return map.hashCode();
}
@Override
public Set<String> immutableKeySet() {
return (map instanceof IProperties<?>) ? ((IProperties<String>) map).immutableKeySet() : map.keySet();
}
@Override
public boolean isEmpty() {
return map.isEmpty();
}
@Override
public boolean isMutable(String key) {
return (map instanceof IProperties<?>) ? ((IProperties<String>) map).isMutable(key) : true;
}
@Override
public Set<String> keySet() {
return map.keySet();
}
@Override
public Set<String> mutableKeySet() {
return (map instanceof IProperties<?>) ? ((IProperties<String>) map).mutableKeySet() : map.keySet();
}
@Override
public Set<String> overlayKeySet() {
if (map instanceof IProperties<?>)
return ((IProperties<String>) map).overlayKeySet();
if (map instanceof MapUnion<?, ?>)
return ((MapUnion<String, String>) map).overlayKeySet();
return map.keySet();
}
@Override
public String put(String key, String value) {
return map.put(key, value);
}
@Override
public String put(String key, String value, boolean mutable) {
if (map instanceof IProperties<?>)
return ((IProperties<String>) map).put(key, value, mutable);
if (!mutable)
throw new UnsupportedOperationException(Messages.Put_immutable);
return map.put(key, value);
}
@Override
public void putAll(Map<? extends String, ? extends String> t) {
map.putAll(t);
}
@Override
public String remove(Object key) {
return map.remove(key);
}
@Override
public void setMutable(String key, boolean flag) throws UnsupportedOperationException {
if (map instanceof IProperties<?>)
((IProperties<String>) map).setMutable(key, flag);
else if (!flag)
throw new UnsupportedOperationException(Messages.SetMutable);
}
@Override
public int size() {
return map.size();
}
@Override
public void store(OutputStream out, String comments) throws IOException {
store(map, out, comments);
}
@Override
public boolean supportsMutability() {
return (map instanceof IProperties<?>) ? ((IProperties<String>) map).supportsMutability() : false;
}
@Override
public Collection<String> values() {
return map.values();
}
}