package it.newinstance.util.rtf; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.Reader; import java.util.HashMap; import java.util.Set; import java.util.TreeSet; public class RTF { private StringBuilder builder; private HashMap bookmarkIndex; private Set replacements = new TreeSet(); private boolean replaced = false; private static String BOOKMARK_START = "\\bkmkstart "; private static String BOOKMARK_END = "\\bkmkend "; private static String FIELD_RESULT = "\\fldrslt"; public RTF(InputStream in) throws IOException { read(in); makeBookmarkIndex(); } private void read(InputStream in) throws IOException { builder = new StringBuilder(16384); Reader reader = new InputStreamReader(in); char[] buffer = new char[4096]; int size; while ((size = reader.read(buffer)) != -1) builder.append((char[]) buffer, 0, size); } private void makeBookmarkIndex() { int idx = 0; bookmarkIndex = new HashMap(); while((idx = builder.indexOf(BOOKMARK_START, idx)) != -1) { Integer foundIndex = new Integer(idx); idx += BOOKMARK_START.length(); StringBuilder bookmarkName = new StringBuilder(); char ch; while ((ch = builder.charAt(idx++)) != '}') bookmarkName.append(ch); bookmarkIndex.put(bookmarkName.toString(), foundIndex); } } public boolean set(String fieldName, String fieldValue) { if (replaced) return false; Integer found = bookmarkIndex.remove(fieldName); // can be set only once if (found == null) return false; int bkmkStart = found.intValue(); String bkmkEndString = BOOKMARK_END + fieldName + "}"; int bkmkEnd = builder.indexOf(bkmkEndString, bkmkStart); if (bkmkEnd == -1) return false; int fldrsltStart = builder.indexOf(FIELD_RESULT, bkmkStart); if (fldrsltStart == -1 || fldrsltStart > bkmkEnd) return false; int start = builder.indexOf("{", fldrsltStart); if (start == -1 || start > bkmkEnd) return false; int end = builder.indexOf("}", start); if (end == -1 || end > bkmkEnd) return false; int replacementStart = builder.indexOf(" ", start) + 1; replacements.add(new Replacement(replacementStart, end, fieldValue)); return true; } public byte[] getBytes() { if (! replaced) { replaced = true; for (Replacement replacement : replacements) replacement.execute(); } return builder.toString().getBytes(); } public void open() throws IOException { shellExec(saveTempFile()); } private String saveTempFile() throws IOException { String tmpDir = System.getProperties().getProperty("java.io.tmpdir"); long time = System.currentTimeMillis(); String filename = tmpDir + "print_" + time + ".rtf"; FileOutputStream out = new FileOutputStream(filename); try { out.write(getBytes()); } finally { out.close(); } return filename; } private void shellExec(String filename) throws IOException { String osName = System.getProperties().getProperty("os.name"); if (osName.indexOf("Windows") != -1) { String cmd = "rundll32 SHELL32.DLL,ShellExec_RunDLL winword " + filename; Runtime.getRuntime().exec(cmd, null, null); } else { throw new UnsupportedOperationException( "Not in Windows; open yourself " + filename); } } private class Replacement implements Comparable { private int start; private int end; private String value; public Replacement(int start, int end, String value) { this.start = start; this.end = end; this.value = value; } public void execute() { builder.replace(start, end, value); } // sorted with descending start: bookmark // replacements are made from last to first public int compareTo(Replacement that) { return (that.start - this.start); } } }