import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.List;
public class SSVCardExtractor {
private static final String VCARD_FILE_SUFFIX = ".vcf";
private String outputCharset = "ascii";
private String inputCharset = "UTF-16LE";
private InputStream input;
private VCardWriter output;
private byte[] start;
private byte[] end;
private interface VCardWriter {
public void write(String vcard) throws IOException;
}
public SSVCardExtractor(String inputPath, String outputPath,
boolean separate, boolean suffixFix) throws IOException {
if (!separate && suffixFix && !outputPath.endsWith(VCARD_FILE_SUFFIX)) {
outputPath = outputPath + VCARD_FILE_SUFFIX;
}
final File outputFile = new File(outputPath);
if (outputFile.exists()) {
throw new IOException("Output path exists: " + outputFile);
}
if (separate) {
outputFile.mkdirs();
this.output = new VCardWriter() {
private File directory = outputFile;
private int index = 0;
@Override
public void write(String vcard) throws IOException {
File file = new File(directory, ++index + VCARD_FILE_SUFFIX);
FileOutputStream stream = new FileOutputStream(file);
try {
stream.write(vcard.getBytes(outputCharset));
stream.flush();
} finally {
stream.close();
}
}
};
} else {
final String outputPathCopy = new String(outputPath);
this.output = new VCardWriter() {
private OutputStream stream = new FileOutputStream(
outputPathCopy);
@Override
public void write(String vcard) throws IOException {
stream.write(vcard.getBytes(outputCharset));
stream.flush();
}
protected void finalize() throws Throwable {
try {
stream.close();
} catch (Exception e) {
// pass
}
}
};
}
this.input = new BufferedInputStream(new FileInputStream(inputPath));
this.start = "BEGIN:VCARD".getBytes(inputCharset);
this.end = "END:VCARD".getBytes(inputCharset);
}
public void extract() throws IOException {
while (skipUntil(start, false) != null) {
byte[] data = skipUntil(end, true);
if (data == null) {
throw new IOException("Unexpected end of stream");
}
String vcard = new String(start, inputCharset)
+ new String(data, inputCharset) + "\r\n";
output.write(vcard);
}
}
private byte[] skipUntil(byte[] bytes, boolean store) throws IOException {
int searchPosition = 0, current;
ByteArrayOutputStream data = new ByteArrayOutputStream();
while ((current = input.read()) >= 0) {
if (store) {
data.write(current);
}
if ((byte) current == bytes[searchPosition]) {
if (++searchPosition == bytes.length) {
return data.toByteArray();
}
} else if (searchPosition != 0) {
searchPosition = 0;
}
}
return null;
}
private static void usageExit(String message) {
PrintStream out = System.out;
if (message != null) {
out.println(message);
}
out.println("Usage: java SSVcardExtractor [OPTIONS] <SBU-FILE> <OUTPUT-PATH>");
out.println("Options:");
out.println(" -s, --separate Write each vcard to separate file.");
out.println(" By default all vcards are written to one file.");
out.println(" --no-suffix-fix Do not add missing "
+ VCARD_FILE_SUFFIX + " suffix.");
out.println(" --debug Print debug messages.");
out.println(" --accept-license Accept license.");
System.exit(1);
}
public static void main(String[] args) {
boolean separate = false;
boolean debug = false;
boolean suffixFix = true;
boolean acceptLicense = false;
List<String> arguments = new ArrayList<String>(2);
for (String argument : args) {
if (argument.equals("--separate") || argument.equals("-s")) {
separate = true;
} else if (argument.equals("--debug")) {
debug = true;
} else if (argument.equals("--no-suffix-fix")) {
suffixFix = false;
} else if (argument.equals("--accept-license")) {
acceptLicense = true;
} else if (argument.startsWith("-")) {
usageExit("Invalid option: " + argument);
} else {
arguments.add(argument);
}
}
if (arguments.size() != 2) {
usageExit("Invalid argument count");
}
try {
SSVCardExtractor extractor = new SSVCardExtractor(arguments.get(0),
arguments.get(1), separate, suffixFix);
extractor.extract();
System.out.println("Extract Complete...");
} catch (IOException e) {
System.out.println(e.getMessage());
System.out.flush();
if (debug) {
e.printStackTrace();
}
}
}
}