3 import java.io.BufferedWriter;
4 import java.io.ByteArrayOutputStream;
5 import java.io.FileOutputStream;
6 import java.io.IOException;
7 import java.io.OutputStream;
8 import java.io.OutputStreamWriter;
12 import javajs.J2SIgnoreImport;
13 import javajs.api.BytePoster;
14 import javajs.api.JmolObjectInterface;
18 * A generic output method. JmolOutputChannel can be used to:
20 * add characters to a StringBuffer
21 * using fileName==null, append() and toString()
23 * add bytes utilizing ByteArrayOutputStream
24 * using writeBytes(), writeByteAsInt(), append()*, and bytesAsArray()
25 * *append() can be used as long as os==ByteArrayOutputStream
26 * or it is not used before one of the writeByte methods.
28 * output characters to a FileOutputStream
29 * using os==FileOutputStream, asWriter==true, append(), and closeChannel()
31 * output bytes to a FileOutputStream
32 * using os==FileOutputStream, writeBytes(), writeByteAsInt(), append(), and closeChannel()
34 * post characters or bytes to a remote server
35 * using fileName=="http://..." or "https://...",
36 * writeBytes(), writeByteAsInt(), append(), and closeChannel()
38 * send characters or bytes to a JavaScript function
39 * when JavaScript and (typeof fileName == "function")
41 * if fileName equals ";base64,", then the data are base64-encoded
42 * prior to writing, and closeChannel() returns the data.
44 * @author hansonr Bob Hanson hansonr@stolaf.edu 9/2013
49 @J2SIgnoreImport({ java.io.FileOutputStream.class })
50 public class OC extends OutputStream {
52 private BytePoster bytePoster; // only necessary for writing to http:// or https://
53 private String fileName;
54 private BufferedWriter bw;
55 private boolean isLocalFile;
56 private int byteCount;
57 private boolean isCanceled;
58 private boolean closed;
59 private OutputStream os;
62 private boolean isBase64;
63 private OutputStream os0;
64 private byte[] bytes; // preset bytes; output only
66 public OC setParams(BytePoster bytePoster, String fileName,
67 boolean asWriter, OutputStream os) {
68 this.bytePoster = bytePoster;
69 this.fileName = fileName;
70 isBase64 = ";base64,".equals(fileName);
77 isLocalFile = (fileName != null && !isRemote(fileName));
78 if (asWriter && !isBase64 && os != null)
79 bw = new BufferedWriter(new OutputStreamWriter(os));
83 public OC setBytes(byte[] b) {
88 public String getFileName() {
92 public String getName() {
93 return (fileName == null ? null : fileName.substring(fileName.lastIndexOf("/") + 1));
96 public int getByteCount() {
102 * @param type user-identified type (PNG, JPG, etc)
104 public void setType(String type) {
108 public String getType() {
113 * will go to string buffer if bw == null and os == null
116 * @return this, for chaining like a standard StringBuffer
119 public OC append(String s) {
123 } else if (os == null) {
128 byte[] b = s.getBytes();
129 os.write(b, 0, b.length);
130 byteCount += b.length;
133 } catch (IOException e) {
136 byteCount += s.length(); // not necessarily exactly correct if unicode
140 public void reset() {
146 private void initOS() {
148 String s = sb.toString();
160 if (os instanceof FileOutputStream) {
162 os = new FileOutputStream(fileName);
168 os = new ByteArrayOutputStream();
171 bw = new BufferedWriter(new OutputStreamWriter(os));
173 } catch (Exception e) {
175 System.out.println(e.toString());
184 public void write(byte[] buf, int i, int len) {
188 os.write(buf, i, len);
189 } catch (IOException e) {
197 public void writeByteAsInt(int b) {
203 * this.os.writeByteAsInt(b);
209 } catch (IOException e) {
216 * Will break JavaScript if used.
224 public void write(int b) {
225 // required by standard ZipOutputStream -- do not use, as it will break JavaScript methods
230 } catch (IOException e) {
236 // * Will break if used; no equivalent in JavaScript.
244 // public void write(byte[] b) {
245 // // not used in JavaScript due to overloading problem there
246 // write(b, 0, b.length);
249 public void cancel() {
254 @SuppressWarnings({ "null", "unused" })
255 public String closeChannel() {
258 // can't cancel file writers
263 } else if (os != null) {
267 if (os0 != null && isCanceled) {
271 } catch (Exception e) {
272 // ignore closing issues
278 if (fileName == null) {
280 String s = getBase64();
288 return closeChannel();
290 return (sb == null ? null : sb.toString());
293 JmolObjectInterface jmol = null;
294 Object _function = null;
298 * jmol = Jmol; _function = (typeof this.fileName == "function" ?
299 * this.fileName : null);
304 String ret = postByteArray(); // unsigned applet could do this
305 if (ret.startsWith("java.net"))
311 Object data = (sb == null ? toByteArray() : sb.toString());
312 if (_function == null)
313 jmol._doAjax(fileName, null, data);
315 jmol._apply(fileName, data);
320 public boolean isBase64() {
324 public String getBase64() {
325 return Base64.getBase64(toByteArray()).toString();
328 public byte[] toByteArray() {
329 return (bytes != null ? bytes : os instanceof ByteArrayOutputStream ? ((ByteArrayOutputStream)os).toByteArray() : null);
334 public void close() {
339 public String toString() {
343 } catch (IOException e) {
347 return closeChannel();
348 return byteCount + " bytes";
351 private String postByteArray() {
352 byte[] bytes = (sb == null ? toByteArray() : sb.toString().getBytes());
353 return bytePoster.postByteArray(fileName, bytes);
356 public final static String[] urlPrefixes = { "http:", "https:", "sftp:", "ftp:",
358 // note that SFTP is not supported
359 public final static int URL_LOCAL = 4;
361 public static boolean isRemote(String fileName) {
362 if (fileName == null)
364 int itype = urlTypeIndex(fileName);
365 return (itype >= 0 && itype != URL_LOCAL);
368 public static boolean isLocal(String fileName) {
369 if (fileName == null)
371 int itype = urlTypeIndex(fileName);
372 return (itype < 0 || itype == URL_LOCAL);
375 public static int urlTypeIndex(String name) {
377 return -2; // local unsigned applet
378 for (int i = 0; i < urlPrefixes.length; ++i) {
379 if (name.startsWith(urlPrefixes[i])) {