2 // Getdown - application installer, patcher and launcher
3 // Copyright (C) 2004-2018 Getdown authors
4 // https://github.com/threerings/getdown/blob/master/LICENSE
6 package com.threerings.getdown.util;
8 public class MessageUtil {
11 * Returns whether or not the provided string is tainted. See {@link #taint}. Null strings
12 * are considered untainted.
14 public static boolean isTainted (String text)
16 return text != null && text.startsWith(TAINT_CHAR);
20 * Call this to "taint" any string that has been entered by an entity outside the application
21 * so that the translation code knows not to attempt to translate this string when doing
22 * recursive translations.
24 public static String taint (Object text)
26 return TAINT_CHAR + text;
30 * Removes the tainting character added to a string by {@link #taint}. If the provided string
31 * is not tainted, this silently returns the originally provided string.
33 public static String untaint (String text)
35 return isTainted(text) ? text.substring(TAINT_CHAR.length()) : text;
39 * Composes a message key with an array of arguments. The message can subsequently be
40 * decomposed and translated without prior knowledge of how many arguments were provided.
42 public static String compose (String key, Object... args)
44 StringBuilder buf = new StringBuilder();
47 for (int i = 0; i < args.length; i++) {
51 // escape the string while adding to the buffer
52 String arg = (args[i] == null) ? "" : String.valueOf(args[i]);
53 int alength = arg.length();
54 for (int p = 0; p < alength; p++) {
55 char ch = arg.charAt(p);
58 } else if (ch == '\\') {
65 return buf.toString();
69 * Compose a message with String args. This is just a convenience so callers do not have to
70 * cast their String[] to an Object[].
72 public static String compose (String key, String... args)
74 return compose(key, (Object[]) args);
78 * A convenience method for calling {@link #compose(String,Object[])} with an array of
79 * arguments that will be automatically tainted (see {@link #taint}).
81 public static String tcompose (String key, Object... args)
83 int acount = args.length;
84 String[] targs = new String[acount];
85 for (int ii = 0; ii < acount; ii++) {
86 targs[ii] = taint(args[ii]);
88 return compose(key, (Object[]) targs);
92 * A convenience method for calling {@link #compose(String,String[])} with an array of argument
93 * that will be automatically tainted.
95 public static String tcompose (String key, String... args)
97 for (int ii = 0, nn = args.length; ii < nn; ii++) {
98 args[ii] = taint(args[ii]);
100 return compose(key, args);
104 * Used to escape single quotes so that they are not interpreted by <code>MessageFormat</code>.
105 * As we assume all single quotes are to be escaped, we cannot use the characters
106 * <code>{</code> and <code>}</code> in our translation strings, but this is a small price to
107 * pay to have to differentiate between messages that will and won't eventually be parsed by a
108 * <code>MessageFormat</code> instance.
110 public static String escape (String message)
112 return message.replace("'", "''");
116 * Unescapes characters that are escaped in a call to compose.
118 public static String unescape (String value)
120 int bsidx = value.indexOf('\\');
125 StringBuilder buf = new StringBuilder();
126 int vlength = value.length();
127 for (int ii = 0; ii < vlength; ii++) {
128 char ch = value.charAt(ii);
129 if (ch != '\\' || ii == vlength-1) {
132 // look at the next character
133 ch = value.charAt(++ii);
134 buf.append((ch == '!') ? '|' : ch);
138 return buf.toString();
141 /** Text prefixed by this character will be considered tainted when doing recursive
142 * translations and won't be translated. */
143 protected static final String TAINT_CHAR = "~";