X-Git-Url: http://git.nikiroo.be/?a=blobdiff_plain;f=src%2Fbe%2Fnikiroo%2Fjvcard%2Fparsers%2FVcard21Parser.java;h=5a07903ae8ca1a558abe78e64ec873ae91f76d5b;hb=59597d59aa262e31c2e1b7f66b4cb299f88ebd1b;hp=f2fd07c5aef8a750bce8db49074113bfadb1ce72;hpb=78e4af97505df331618f9c13dd5d98440d364764;p=jvcard.git diff --git a/src/be/nikiroo/jvcard/parsers/Vcard21Parser.java b/src/be/nikiroo/jvcard/parsers/Vcard21Parser.java index f2fd07c..5a07903 100644 --- a/src/be/nikiroo/jvcard/parsers/Vcard21Parser.java +++ b/src/be/nikiroo/jvcard/parsers/Vcard21Parser.java @@ -1,5 +1,8 @@ package be.nikiroo.jvcard.parsers; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; import java.util.Iterator; import java.util.LinkedList; import java.util.List; @@ -10,10 +13,20 @@ import be.nikiroo.jvcard.Data; import be.nikiroo.jvcard.TypeInfo; public class Vcard21Parser { - public static List parse(Iterable textData) { + /** + * 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 parseContact(Iterable textData) { Iterator lines = textData.iterator(); List contacts = new LinkedList(); - List datas = null; + List datas = null; String nextRawLine = null; if (lines.hasNext()) { @@ -43,14 +56,14 @@ public class Vcard21Parser { String line = rawLine.toString(); if (line.equals("BEGIN:VCARD")) { - datas = new LinkedList(); + datas = new LinkedList(); } else if (line.equals("END:VCARD")) { if (datas == null) { // BAD INPUT FILE. IGNORE. System.err .println("VCARD Parser warning: END:VCARD seen before any VCARD:BEGIN"); } else { - contacts.add(new Contact(datas)); + contacts.add(new Contact(parseData(datas))); } } else { if (datas == null) { @@ -58,96 +71,219 @@ public class Vcard21Parser { System.err .println("VCARD Parser warning: data seen before any VCARD:BEGIN"); } else { - List types = new LinkedList(); - String name = ""; - String value = ""; - String group = ""; - - if (line.contains(":")) { - String rest = line.split(":")[0]; - value = line.substring(rest.length() + 1); - - if (rest.contains(";")) { - String tab[] = rest.split(";"); - name = tab[0]; - - for (int i = 1; i < tab.length; i++) { - if (tab[i].contains("=")) { - String tname = tab[i].split("=")[0]; - String tvalue = tab[i].substring(tname - .length() + 1); - types.add(new TypeInfo(tname, tvalue)); - } else { - types.add(new TypeInfo(tab[i], "")); - } - } + datas.add(line); + } + } + } + + return contacts; + } + + /** + * 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 parseData(Iterable textData) { + List datas = new LinkedList(); + + for (String line : textData) { + List types = new LinkedList(); + String name = ""; + String value = ""; + String group = ""; + + if (line.contains(":")) { + int colIndex = line.indexOf(':'); + String rest = line.substring(0, colIndex); + value = line.substring(colIndex + 1); + + if (rest.contains(";")) { + String tab[] = rest.split(";"); + name = tab[0]; + + for (int i = 1; i < tab.length; i++) { + if (tab[i].contains("=")) { + int equIndex = tab[i].indexOf('='); + String tname = tab[i].substring(0, equIndex); + String tvalue = tab[i].substring(equIndex + 1); + types.add(new TypeInfo(tname, tvalue)); } else { - name = rest; + types.add(new TypeInfo(tab[i], "")); } - } else { - name = line; - } - - if (name.contains(".")) { - group = name.split("\\.")[0]; - name = name.substring(group.length() + 1); } - - datas.add(new Data(types, name, value, group)); + } else { + name = rest; } + } else { + name = line; + } + + if (name.contains(".")) { + int dotIndex = name.indexOf('.'); + group = name.substring(0, dotIndex); + name = name.substring(dotIndex + 1); } + + datas.add(new Data(types, name, value, group)); } - return contacts; + return datas; + } + + /** + * Write the given {@link Card} in the {@link Appendable}. + * + * @param writer + * the {@link Appendable} + * @param card + * the {@link Card} to write + * + * @throws IOException + * in case of IO error + */ + public static void write(Appendable writer, Card card) throws IOException { + for (Contact contact : card) { + write(writer, contact, -1); + } } - // -1 = no bkeys - public static String toString(Contact contact, int startingBKey) { - StringBuilder builder = new StringBuilder(); - - builder.append("BEGIN:VCARD"); - 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); - if (data.getGroup() != null && !data.getGroup().trim().equals("")) { - builder.append(data.getGroup().trim()); - builder.append('.'); + /** + * Write the given {@link Contact} in the {@link Appendable}. + * + * @param writer + * the {@link Appendable} + * @param contact + * the {@link Contact} to write + * @param startingBKey + * the starting BKey number (all the other will follow) or -1 for + * no BKey + * + * @throws IOException + * in case of IO error + */ + public static void write(Appendable writer, Contact contact, + int startingBKey) throws IOException { + + writer.append("BEGIN:VCARD\r\n"); + writer.append("VERSION:2.1\r\n"); + for (Data data : contact) { + write(writer, data); + } + writer.append("END:VCARD\r\n"); + } + + /** + * Write the given {@link Data} in the {@link Appendable}. + * + * @param writer + * the {@link Appendable} + * @param data + * the {@link Data} to write + * + * @throws IOException + * in case of IO error + */ + public static void write(Appendable writer, Data data) throws IOException { + StringBuilder dataBuilder = new StringBuilder(); + if (data.getGroup() != null && !data.getGroup().trim().equals("")) { + dataBuilder.append(data.getGroup().trim()); + dataBuilder.append('.'); + } + dataBuilder.append(data.getName()); + for (TypeInfo type : data) { + dataBuilder.append(';'); + dataBuilder.append(type.getName()); + if (type.getValue() != null && !type.getValue().trim().equals("")) { + dataBuilder.append('='); + dataBuilder.append(type.getRawValue()); } - builder.append(data.getName()); - for (int indexType = 0; indexType < data.size(); indexType++) { - TypeInfo type = data.get(indexType); - builder.append(';'); - builder.append(type.getName()); - if (type.getValue() != null - && !type.getValue().trim().equals("")) { - builder.append('='); - builder.append(type.getValue()); + } + dataBuilder.append(':'); + + // TODO: bkey! + dataBuilder.append(data.getRawValue()); + + // 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) + int previous = 0; + for (int index = 0; index < dataBuilder.length(); previous = index) { + index += 74; + if (previous > 0) + index--; // the space takes 1 + if (dataBuilder.length() > index) { + char car = dataBuilder.charAt(index - 1); + // RFC forbids cutting a character in 2 + if (Character.isHighSurrogate(car)) { + index++; } } - builder.append(':'); - // TODO: bkey! - builder.append(data.getValue()); - builder.append("\r\n"); + index = Math.min(index, dataBuilder.length()); + if (previous > 0) + writer.append(' '); + writer.append(dataBuilder, previous, index); + writer.append("\r\n"); } - builder.append("END:VCARD"); - builder.append("\r\n"); - - return builder.toString(); } - public static String toString(Card card) { - StringBuilder builder = new StringBuilder(); + /** + * Clone the given {@link Card} by exporting then importing it again in VCF. + * + * @param c + * the {@link Card} to clone + * + * @return the clone {@link Contact} + */ + public static Card clone(Card c) { + try { + File tmp = File.createTempFile("clone", ".vcf"); + c.saveAs(tmp, Format.VCard21); + + Card clone = new Card(tmp, Format.VCard21); + clone.unlink(); + tmp.delete(); - for (int index = 0; index < card.size(); index++) { - builder.append(toString(card.get(index), -1)); + return clone; + } catch (IOException e) { + e.printStackTrace(); } - builder.append("\r\n"); + return null; + } + + /** + * Clone the given {@link Contact} by exporting then importing it again in + * VCF. + * + * @param c + * the {@link Contact} to clone + * + * @return the clone {@link Contact} + */ + public static Contact clone(Contact c) { + try { + File tmp = File.createTempFile("clone", ".vcf"); + FileWriter writer = new FileWriter(tmp); + write(writer, c, -1); + writer.close(); + + Card clone = new Card(tmp, Format.VCard21); + clone.unlink(); + tmp.delete(); + + return clone.remove(0); + } catch (IOException e) { + e.printStackTrace(); + } - return builder.toString(); + return null; } /**