import java.util.PropertyResourceBundle;
import java.util.ResourceBundle;
+import be.nikiroo.utils.resources.Meta.Format;
+
/**
* This class encapsulate a {@link ResourceBundle} in UTF-8. It allows to
* retrieve values associated to an enumeration, and allows some additional
*
* @return TRUE if the setting is set
*/
- public boolean iSet(E id, boolean includeDefaultValue) {
- if (getString(id.toString(), null) == null) {
- if (!includeDefaultValue || getString(id) == null) {
+ public boolean isSet(E id, boolean includeDefaultValue) {
+ return isSet(id.name(), includeDefaultValue);
+ }
+
+ /**
+ * Check if the setting is set into this {@link Bundle}.
+ *
+ * @param id
+ * the id of the setting to check
+ * @param includeDefaultValue
+ * TRUE to only return false when the setting is not set AND
+ * there is no default value
+ *
+ * @return TRUE if the setting is set
+ */
+ protected boolean isSet(String name, boolean includeDefaultValue) {
+ if (getString(name, null) == null) {
+ if (!includeDefaultValue || getString(name, "") == null) {
return false;
}
}
public String getString(E id, String def) {
String rep = getString(id.name(), null);
if (rep == null) {
- MetaInfo<E> info = new MetaInfo<E>(type, this, id);
- rep = info.getDefaultString();
+ try {
+ Meta meta = type.getDeclaredField(id.name()).getAnnotation(
+ Meta.class);
+ rep = meta.def();
+ } catch (NoSuchFieldException e) {
+ } catch (SecurityException e) {
+ }
}
if (rep == null) {
// Default, empty values -> NULL
if (desc.length() + list.length + def.length() == 0 && !group
- && nullable && format == Meta.Format.STRING) {
+ && nullable && format == Format.STRING) {
return null;
}
StringBuilder builder = new StringBuilder();
- builder.append("# ").append(desc);
- if (desc.length() > 20) {
- builder.append("\n#");
+ for (String line : desc.split("\n")) {
+ builder.append("# ").append(line).append("\n");
}
if (group) {
- builder.append("This item is used as a group, its content is not expected to be used.");
+ builder.append("# This item is used as a group, its content is not expected to be used.");
} else {
- builder.append(" (FORMAT: ").append(format)
- .append(nullable ? "" : " (required)");
+ builder.append("# (FORMAT: ").append(format)
+ .append(nullable ? "" : ", required");
builder.append(") ");
if (list.length > 0) {
- builder.append("\n# ALLOWED VALUES:");
+ builder.append("\n# ALLOWED VALUES: ");
+ boolean first = true;
for (String value : list) {
- builder.append(" \"").append(value).append("\"");
+ if (!first) {
+ builder.append(", ");
+ }
+ builder.append(BundleHelper.escape(value));
+ first = false;
}
}
if (array) {
- builder.append("\n# (This item accept a list of comma-separated values)");
+ builder.append("\n# (This item accepts a list of escaped comma-separated values)");
}
}
}
/**
- * Write the given id to the config file, i.e., "MY_ID = my_curent_value"
- * followed by a new line
+ * Write the given data to the config file, i.e., "MY_ID = my_curent_value"
+ * followed by a new line.
+ * <p>
+ * Will prepend a # sign if the is is not set (see
+ * {@link Bundle#isSet(Enum, boolean)}).
*
* @param writer
* the {@link Writer} to write into
* in case of IO error
*/
protected void writeValue(Writer writer, E id) throws IOException {
- writeValue(writer, id.name(), getString(id));
+ boolean set = isSet(id, false);
+ writeValue(writer, id.name(), getString(id), set);
}
/**
* Write the given data to the config file, i.e., "MY_ID = my_curent_value"
- * followed by a new line
+ * followed by a new line.
+ * <p>
+ * Will prepend a # sign if the is is not set.
*
* @param writer
* the {@link Writer} to write into
* the id to write
* @param value
* the id's value
+ * @param set
+ * the value is set in this {@link Bundle}
*
* @throws IOException
* in case of IO error
*/
- protected void writeValue(Writer writer, String id, String value)
- throws IOException {
+ protected void writeValue(Writer writer, String id, String value,
+ boolean set) throws IOException {
+
+ if (!set) {
+ writer.write('#');
+ }
+
writer.write(id);
writer.write(" = ");
File file = getPropertyFile(dir, name.name(), locale);
if (file != null) {
Reader reader = new InputStreamReader(new FileInputStream(
- file), "UTF8");
+ file), "UTF-8");
resetMap(new PropertyResourceBundle(reader));
found = true;
}
/**
* Reset the backing map to the content of the given bundle, or with default
- * valiues if bundle is NULL.
+ * values if bundle is NULL.
*
* @param bundle
* the bundle to copy
char car = str.charAt(i);
if (prevIsBackSlash) {
+ // We don't process it here
builder.append(car);
prevIsBackSlash = false;
} else {
switch (car) {
case '"':
+ // We don't process it here
+ builder.append(car);
+
if (inQuote) {
- list.add(builder.toString());
+ list.add(unescape(builder.toString()));
builder.setLength(0);
}
inQuote = !inQuote;
break;
case '\\':
+ // We don't process it here
+ builder.append(car);
prevIsBackSlash = true;
break;
case ' ':
if (builder.length() > 0) {
builder.append(", ");
}
- builder.append('"')//
- .append(item.replace("\\", "\\\\").replace("\"", "\\\""))//
- .append('"');
+ builder.append(escape(item));
+ }
+
+ return builder.toString();
+ }
+
+ /**
+ * Escape the given value for list formating (no \\, no \n).
+ * <p>
+ * You can unescape it with {@link BundleHelper#unescape(String)}
+ *
+ * @param value
+ * the value to escape
+ *
+ * @return an escaped value that can unquoted by the reverse operation
+ * {@link BundleHelper#unescape(String)}
+ */
+ static public String escape(String value) {
+ return '"' + value//
+ .replace("\\", "\\\\") //
+ .replace("\"", "\\\"") //
+ .replace("\n", "\\\n") //
+ .replace("\r", "\\\r") //
+ + '"';
+ }
+
+ /**
+ * Unescape the given value for list formating (change \\n into \n and so
+ * on).
+ * <p>
+ * You can escape it with {@link BundleHelper#escape(String)}
+ *
+ * @param value
+ * the value to escape
+ *
+ * @return an unescaped value that can reverted by the reverse operation
+ * {@link BundleHelper#escape(String)}, or NULL if it was badly
+ * formated
+ */
+ static public String unescape(String value) {
+ if (value.length() < 2 || !value.startsWith("\"")
+ || !value.endsWith("\"")) {
+ // Bad format
+ return null;
+ }
+
+ value = value.substring(1, value.length() - 2);
+
+ boolean prevIsBackslash = false;
+ StringBuilder builder = new StringBuilder();
+ for (char car : value.toCharArray()) {
+ if (prevIsBackslash) {
+ switch (car) {
+ case 'n':
+ case 'N':
+ builder.append('\n');
+ break;
+ case 'r':
+ case 'R':
+ builder.append('\r');
+ break;
+ default: // includes \ and "
+ builder.append(car);
+ break;
+ }
+ } else {
+ if (car == '\\') {
+ prevIsBackslash = true;
+ } else {
+ builder.append(car);
+ }
+ }
+ }
+
+ if (prevIsBackslash) {
+ // Bad format
+ return null;
}
return builder.toString();