/*
* Vitry, copyright (C) Hans Hoglund 2011
*
* This program 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.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* See COPYING.txt for details.
*/
package vitry.runtime.util;
import java.io.IOException;
import java.io.StringWriter;
import java.io.Writer;
import java.util.Locale;
import vitry.runtime.error.ParseError;
public class Strings
{
private Strings() {
}
public static String join(Object[] elements)
{
return join (elements, "", ", ", "");
}
public static String join(Iterable<?> elements)
{
return join (elements, "", ", ", "");
}
public static String join(Object[] elements, String start, String delim, String end)
{
return join(java.util.Arrays.asList(elements), start, delim, end);
}
public static String join(Iterable<?> elements, String start, String delim, String end)
{
StringBuilder strb = new StringBuilder();
boolean first = true;
strb.append(start);
for (Object e : elements)
{
if (first)
first = false;
else
strb.append(delim);
strb.append(e);
}
strb.append(end);
return strb.toString();
}
public static String limit(String s, int maxLength)
{
if (s.length() > maxLength)
return s.substring(0, maxLength) + "...";
else
return s;
}
public static String unescape(String str)
{
if (str == null)
{
return null;
}
StringWriter writer = null;
try
{
writer = new StringWriter(str.length());
unescape(writer, str);
}
catch (IOException ioe)
{
// this should never ever happen while writing to a StringWriter
assert false;
}
return writer.toString();
}
public static void unescape(Writer out, String str) throws IOException
{
if (out == null)
{
throw new IllegalArgumentException("The Writer must not be null");
}
if (str == null)
{
return;
}
int sz = str.length();
StringBuilder unicode = new StringBuilder(4);
boolean hadSlash = false;
boolean inUnicode = false;
for (int i = 0; i < sz; i++)
{
char ch = str.charAt(i);
if (inUnicode)
{
// if in unicode, then we're reading unicode
// values in somehow
unicode.append(ch);
if (unicode.length() == 4)
{
// unicode now contains the four hex digits
// which represents our unicode character
try
{
int value = Integer.parseInt(unicode.toString(), 16);
out.write((char) value);
unicode.setLength(0);
inUnicode = false;
hadSlash = false;
}
catch (NumberFormatException nfe)
{
throw new ParseError("Unable to parse unicode value: " + unicode);
}
}
continue;
}
if (hadSlash)
{
// handle an escaped value
hadSlash = false;
switch (ch) {
case '\\':
out.write('\\');
break;
case '\'':
out.write('\'');
break;
case '\"':
out.write('"');
break;
case 'r':
out.write('\r');
break;
case 'f':
out.write('\f');
break;
case 't':
out.write('\t');
break;
case 'n':
out.write('\n');
break;
case 'b':
out.write('\b');
break;
case 'u': {
// uh-oh, we're in unicode country....
inUnicode = true;
break;
}
default:
out.write(ch);
break;
}
continue;
}
else if (ch == '\\')
{
hadSlash = true;
continue;
}
out.write(ch);
}
if (hadSlash)
{
// then we're in the weird case of a \ at the end of the
// string, let's output it anyway.
out.write('\\');
}
}
public static String escape(String str) {
return escapeJavaStyleString(str, false, false);
}
public static void escape(Writer out, String str) throws IOException {
escapeJavaStyleString(out, str, false, false);
}
/**
* <p>Worker method for the {@link #escapeJavaScript(String)} method.</p>
*
* @param str String to escape values in, may be null
* @param escapeSingleQuotes escapes single quotes if <code>true</code>
* @param escapeForwardSlash TODO
* @return the escaped string
*/
private static String escapeJavaStyleString(String str, boolean escapeSingleQuotes, boolean escapeForwardSlash) {
if (str == null) {
return null;
}
try {
StringWriter writer = new StringWriter(str.length() * 2);
escapeJavaStyleString(writer, str, escapeSingleQuotes, escapeForwardSlash);
return writer.toString();
} catch (IOException ioe) {
// this should never ever happen while writing to a StringWriter
return Utils.assertFalse();
}
}
/**
* <p>Worker method for the {@link #escapeJavaScript(String)} method.</p>
*
* @param out write to receieve the escaped string
* @param str String to escape values in, may be null
* @param escapeSingleQuote escapes single quotes if <code>true</code>
* @param escapeForwardSlash TODO
* @throws IOException if an IOException occurs
*/
private static void escapeJavaStyleString(Writer out, String str, boolean escapeSingleQuote,
boolean escapeForwardSlash) throws IOException {
if (out == null) {
throw new IllegalArgumentException("The Writer must not be null");
}
if (str == null) {
return;
}
int sz;
sz = str.length();
for (int i = 0; i < sz; i++) {
char ch = str.charAt(i);
// handle unicode
if (ch > 0xfff) {
out.write("\\u" + hex(ch));
} else if (ch > 0xff) {
out.write("\\u0" + hex(ch));
} else if (ch > 0x7f) {
out.write("\\u00" + hex(ch));
} else if (ch < 32) {
switch (ch) {
case '\b' :
out.write('\\');
out.write('b');
break;
case '\n' :
out.write('\\');
out.write('n');
break;
case '\t' :
out.write('\\');
out.write('t');
break;
case '\f' :
out.write('\\');
out.write('f');
break;
case '\r' :
out.write('\\');
out.write('r');
break;
default :
if (ch > 0xf) {
out.write("\\u00" + hex(ch));
} else {
out.write("\\u000" + hex(ch));
}
break;
}
} else {
switch (ch) {
case '\'' :
if (escapeSingleQuote) {
out.write('\\');
}
out.write('\'');
break;
case '"' :
out.write('\\');
out.write('"');
break;
case '\\' :
out.write('\\');
out.write('\\');
break;
case '/' :
if (escapeForwardSlash) {
out.write('\\');
}
out.write('/');
break;
default :
out.write(ch);
break;
}
}
}
}
private static String hex(char ch) {
return Integer.toHexString(ch).toUpperCase(Locale.ENGLISH);
}
}