package be.nikiroo.jvcard;
-import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
-import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.IOException;
-import java.io.InputStreamReader;
import java.security.InvalidParameterException;
-import java.util.LinkedList;
import java.util.List;
import be.nikiroo.jvcard.parsers.Format;
* if format is NULL
*/
public Card(File file, Format format) throws IOException {
- this(load(file, format));
+ this(Parser.parse(file, format));
if (file != null) {
if (file.exists()) {
* Save the {@link Card} to the given {@link File} with the given
* {@link Format}.
*
- * @param output
+ * @param file
* the output to save to
* @param format
* the {@link Format} to use
* @throws IOException
* in case of IO errors
*/
- public boolean saveAs(File output, Format format) throws IOException {
- if (output == null)
+ public boolean saveAs(File file, Format format) throws IOException {
+ if (file == null)
return false;
- BufferedWriter writer = new BufferedWriter(new FileWriter(output));
+ BufferedWriter writer = new BufferedWriter(new FileWriter(file));
writer.append(toString(format));
writer.close();
- if (output.getCanonicalPath().equals(this.file.getCanonicalPath())) {
+ if (this.file != null
+ && file.getCanonicalPath().equals(this.file.getCanonicalPath())) {
setPristine();
}
if (file == null)
return false;
- this.replaceListContent(load(file, format));
+ this.replaceListContent(Parser.parse(file, format));
setPristine();
return true;
}
public String getState() {
return "" + name + format;
}
-
- /**
- * Load the data from the given {@link File} under the given {@link Format}.
- *
- * @param file
- * the input to load from
- * @param format
- * the {@link Format} to load as
- *
- * @return the list of elements
- *
- * @throws IOException
- * in case of IO error
- */
- private static List<Contact> load(File file, Format format)
- throws IOException {
- List<String> lines = null;
-
- if (file != null && file.exists()) {
- BufferedReader buffer = new BufferedReader(new InputStreamReader(
- new FileInputStream(file), "UTF-8"));
- lines = new LinkedList<String>();
- for (String line = buffer.readLine(); line != null; line = buffer
- .readLine()) {
- lines.add(line);
- }
- buffer.close();
- }
-
- if (lines == null)
- return new LinkedList<Contact>();
-
- return Parser.parse(lines, format);
- }
}
* @param types
* the types of this {@link Data}
* @param name
- * its name
+ * its name (<b>MUST NOT</b> be NULL)
* @param value
- * its value
+ * its value (<b>MUST NOT</b> be NULL)
* @param group
- * its group if any
+ * its group if any (or NULL if none)
*/
public Data(List<TypeInfo> types, String name, String value, String group) {
super(types);
- this.name = name;
- this.value = value;
+ this.name = name.toUpperCase();
+ this.value = value.toString(); // crash NOW if null
this.group = group;
b64 = -1;
private String name;
private String value;
+ /**
+ * Create a new {@link TypeInfo}.
+ *
+ * @param name
+ * the name of this {@link TypeInfo} (<b>MUST NOT</b> be NULL)
+ * @param value
+ * its value (<b>MUST NOT</b> be NULL)
+ */
@SuppressWarnings("unchecked")
public TypeInfo(String name, String value) {
super(null);
- this.name = name;
- this.value = value;
+ this.name = name.toUpperCase();
+ this.value = value.toString(); // crash NOW if null
}
+ /**
+ * Return the name.
+ *
+ * @return the name
+ */
public String getName() {
return name;
}
+ /**
+ * Return the value.
+ *
+ * @return the value
+ */
public String getValue() {
return value;
}
package be.nikiroo.jvcard.parsers;
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
import java.security.InvalidParameterException;
+import java.util.LinkedList;
import java.util.List;
import be.nikiroo.jvcard.Card;
public class Parser {
+ /**
+ * Load the data from the given {@link File} under the given {@link Format}.
+ *
+ * @param file
+ * the input to load from
+ * @param format
+ * the {@link Format} to load as
+ *
+ * @return the list of elements
+ *
+ * @throws IOException
+ * in case of IO error
+ */
+ public static List<Contact> parse(File file, Format format)
+ throws IOException {
+ List<String> lines = null;
+
+ if (file != null && file.exists()) {
+ BufferedReader buffer = new BufferedReader(new InputStreamReader(
+ new FileInputStream(file), "UTF-8"));
+ lines = new LinkedList<String>();
+ for (String line = buffer.readLine(); line != null; line = buffer
+ .readLine()) {
+ lines.add(line);
+ }
+ buffer.close();
+ }
+
+ if (lines == null)
+ return new LinkedList<Contact>();
+
+ return parse(lines, format);
+ }
+
+ /**
+ * Load the given data from under the given {@link Format}.
+ *
+ * @param lines
+ * the input to load from
+ * @param format
+ * the {@link Format} to load as
+ *
+ * @return the list of elements
+ */
public static List<Contact> parse(List<String> lines, Format format) {
switch (format) {
case VCard21:
builder.append("\r\n");
builder.append("VERSION:2.1");
builder.append("\r\n");
- for (int indexData = 0; indexData < contact.size(); indexData++) {
- Data data = contact.get(indexData);
+ for (Data data : contact) {
+ StringBuilder dataBuilder = new StringBuilder();
if (data.getGroup() != null && !data.getGroup().trim().equals("")) {
- builder.append(data.getGroup().trim());
- builder.append('.');
+ dataBuilder.append(data.getGroup().trim());
+ dataBuilder.append('.');
}
- builder.append(data.getName());
- for (int indexType = 0; indexType < data.size(); indexType++) {
- TypeInfo type = data.get(indexType);
- builder.append(';');
- builder.append(type.getName());
+ dataBuilder.append(data.getName());
+ for (TypeInfo type : data) {
+ dataBuilder.append(';');
+ dataBuilder.append(type.getName());
if (type.getValue() != null
&& !type.getValue().trim().equals("")) {
- builder.append('=');
- builder.append(type.getValue());
+ dataBuilder.append('=');
+ dataBuilder.append(type.getValue());
}
}
- builder.append(':');
+ dataBuilder.append(':');
// TODO: bkey!
- builder.append(data.getValue());
- builder.append("\r\n");
+ dataBuilder.append(data.getValue());
+
+ // RFC says: Content lines SHOULD be folded to a maximum width of 75
+ // octets -> since it is SHOULD, we will just cut it as 74/75 chars
+ // depending if the last one fits in one char (note: chars != octet)
+ boolean continuation = false;
+ while (dataBuilder.length() > 0) {
+ int stop = 74;
+ if (continuation)
+ stop--; // the space takes 1
+ if (dataBuilder.length() > stop) {
+ char car = dataBuilder.charAt(stop - 1);
+ // RFC forbids cutting a character in 2
+ if (Character.isHighSurrogate(car)) {
+ stop++;
+ }
+ }
+
+ stop = Math.min(stop, dataBuilder.length());
+ if (continuation)
+ builder.append(' ');
+ builder.append(dataBuilder, 0, stop);
+ builder.append("\r\n");
+ dataBuilder.delete(0, stop);
+
+ continuation = true;
+ }
}
builder.append("END:VCARD");
builder.append("\r\n");
public static String toString(Card card) {
StringBuilder builder = new StringBuilder();
- for (int index = 0; index < card.size(); index++) {
- builder.append(toString(card.get(index), -1));
+ for (Contact contact : card) {
+ builder.append(toString(contact, -1));
}
builder.append("\r\n");
public class Bundles {
static private String confDir = getConfDir();
+ // TODO: rename to bundle, use it as base for i18n.Trans, create one for
+ // each resource
+ private int TODO;
+
/**
* Return the non-localised bundle of the given name.
*
# - WHITE: one of the ANSI colour names, in upper case
# - @RRGGBB: a RGB code we will try to match using one of the 256 Terminal colours
# - #RRGGBB: an exact RGB colour (please make sure your terminal supports this)
+# - 255: one of the 256 indexed colours of the terminal (the 16 first colours are theme-based)
#
# ...and thus either for xxx_FG (foreground colour) or xxx_BG (background colour)
int g = Integer.parseInt(value.substring(3, 5), 16);
int b = Integer.parseInt(value.substring(5, 7), 16);
return new TextColor.RGB(r, g, b);
+ } else if (value.replaceAll("[0-9]*", "").length() == 0) {
+ return new TextColor.Indexed(Integer.parseInt(value));
} else {
return TextColor.ANSI.valueOf(value);
}
package be.nikiroo.jvcard.tui.panes;
import java.awt.Image;
+import java.io.ByteArrayInputStream;
import java.util.LinkedList;
import java.util.List;
+import javax.imageio.ImageIO;
import javax.xml.bind.DatatypeConverter;
-import javax.swing.ImageIcon;
import be.nikiroo.jvcard.Contact;
import be.nikiroo.jvcard.Data;
if (encoding != null && encoding.getValue() != null
&& encoding.getValue().equalsIgnoreCase("b")) {
- image = new ImageIcon(DatatypeConverter.parseBase64Binary(
- photo.getValue())).getImage();
+ try {
+ image = ImageIO.read(new ByteArrayInputStream(
+ DatatypeConverter.parseBase64Binary(photo
+ .getValue())));
+ image.toString();
+ } catch (Exception e) {
+ System.err.println("Cannot parse image for contact: "
+ + contact.getPreferredDataValue("UID"));
+ }
}
}
}