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