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;
9 import javajs.J2SIgnoreImport;
10 import javajs.api.BytePoster;
11 import javajs.api.GenericOutputChannel;
12 import javajs.api.js.J2SObjectInterface;
16 * A generic output method. JmolOutputChannel can be used to:
18 * add characters to a StringBuffer
19 * using fileName==null, append() and toString()
21 * add bytes utilizing ByteArrayOutputStream
22 * using writeBytes(), writeByteAsInt(), append()*, and bytesAsArray()
23 * *append() can be used as long as os==ByteArrayOutputStream
24 * or it is not used before one of the writeByte methods.
26 * output characters to a FileOutputStream
27 * using os==FileOutputStream, asWriter==true, append(), and closeChannel()
29 * output bytes to a FileOutputStream
30 * using os==FileOutputStream, writeBytes(), writeByteAsInt(), append(), and closeChannel()
32 * post characters or bytes to a remote server
33 * using fileName=="http://..." or "https://...",
34 * writeBytes(), writeByteAsInt(), append(), and closeChannel()
36 * send characters or bytes to a JavaScript function
37 * when JavaScript and (typeof fileName == "function")
39 * if fileName equals ";base64,", then the data are base64-encoded
40 * prior to writing, and closeChannel() returns the data.
42 * @author hansonr Bob Hanson hansonr@stolaf.edu 9/2013
47 @J2SIgnoreImport({ java.io.FileOutputStream.class })
48 public class OC extends OutputStream implements GenericOutputChannel {
50 private BytePoster bytePoster; // only necessary for writing to http:// or https://
51 private String fileName;
52 private BufferedWriter bw;
53 private boolean isLocalFile;
54 private int byteCount;
55 private boolean isCanceled;
56 private boolean closed;
57 private OutputStream os;
60 private boolean isBase64;
61 private OutputStream os0;
62 private byte[] bytes; // preset bytes; output only
64 public boolean bigEndian = true;
67 public boolean isBigEndian() {
71 public void setBigEndian(boolean TF) {
75 public OC setParams(BytePoster bytePoster, String fileName,
76 boolean asWriter, OutputStream os) {
77 this.bytePoster = bytePoster;
78 isBase64 = ";base64,".equals(fileName);
84 this.fileName = fileName;
86 isLocalFile = (fileName != null && !isRemote(fileName));
87 if (asWriter && !isBase64 && os != null)
88 bw = Rdr.getBufferedWriter(os, null);
92 public OC setBytes(byte[] b) {
97 public String getFileName() {
101 public String getName() {
102 return (fileName == null ? null : fileName.substring(fileName.lastIndexOf("/") + 1));
105 public int getByteCount() {
111 * @param type user-identified type (PNG, JPG, etc)
113 public void setType(String type) {
117 public String getType() {
122 * will go to string buffer if bw == null and os == null
125 * @return this, for chaining like a standard StringBuffer
128 public OC append(String s) {
132 } else if (os == null) {
137 byte[] b = s.getBytes();
138 os.write(b, 0, b.length);
139 byteCount += b.length;
142 } catch (IOException e) {
145 byteCount += s.length(); // not necessarily exactly correct if unicode
150 public void reset() {
156 private void initOS() {
158 String s = sb.toString();
170 if (os instanceof FileOutputStream) {
172 os = new FileOutputStream(fileName);
178 os = new ByteArrayOutputStream();
181 bw = Rdr.getBufferedWriter(os, null);
183 } catch (Exception e) {
185 System.out.println(e.toString());
194 public void writeByteAsInt(int b) {
200 } catch (IOException e) {
207 public void write(byte[] buf, int i, int len) {
211 os.write(buf, i, len);
212 } catch (IOException e) {
218 public void writeShort(short i) {
220 writeByteAsInt(i >> 8);
224 writeByteAsInt(i >> 8);
229 public void writeLong(long b) {
231 writeInt((int) ((b >> 32) & 0xFFFFFFFFl));
232 writeInt((int) (b & 0xFFFFFFFFl));
234 writeByteAsInt((int) (b >> 56));
235 writeByteAsInt((int) (b >> 48));
236 writeByteAsInt((int) (b >> 40));
237 writeByteAsInt((int) (b >> 32));
238 writeByteAsInt((int) (b >> 24));
239 writeByteAsInt((int) (b >> 16));
240 writeByteAsInt((int) (b >> 8));
241 writeByteAsInt((int) b);
245 public void write(int b) {
246 // required by standard ZipOutputStream -- do not use, as it will break JavaScript methods
251 } catch (IOException e) {
256 public void write(byte[] b) {
257 // not used in JavaScript due to overloading problem there
258 write(b, 0, b.length);
261 public void cancel() {
267 @SuppressWarnings({ "unused" })
268 public String closeChannel() {
271 // can't cancel file writers
276 } else if (os != null) {
280 if (os0 != null && isCanceled) {
284 } catch (Exception e) {
285 // ignore closing issues
291 if (fileName == null) {
293 String s = getBase64();
301 return closeChannel();
303 return (sb == null ? null : sb.toString());
306 J2SObjectInterface jmol = null;
307 Object _function = null;
311 * jmol = self.J2S || Jmol; _function = (typeof this.fileName == "function" ?
312 * this.fileName : null);
317 String ret = postByteArray(); // unsigned applet could do this
318 if (ret.startsWith("java.net"))
324 Object data = (sb == null ? toByteArray() : sb.toString());
325 if (_function == null)
326 jmol._doAjax(fileName, null, data, sb == null);
328 jmol._apply(_function, data);
333 public boolean isBase64() {
337 public String getBase64() {
338 return Base64.getBase64(toByteArray()).toString();
341 public byte[] toByteArray() {
342 return (bytes != null ? bytes : os instanceof ByteArrayOutputStream ? ((ByteArrayOutputStream)os).toByteArray() : null);
347 public void close() {
352 public String toString() {
356 } catch (IOException e) {
360 return closeChannel();
361 return byteCount + " bytes";
364 private String postByteArray() {
365 byte[] bytes = (sb == null ? toByteArray() : sb.toString().getBytes());
366 return bytePoster.postByteArray(fileName, bytes);
369 public final static String[] urlPrefixes = { "http:", "https:", "sftp:", "ftp:",
371 // note that SFTP is not supported
372 public final static int URL_LOCAL = 4;
374 public static boolean isRemote(String fileName) {
375 if (fileName == null)
377 int itype = urlTypeIndex(fileName);
378 return (itype >= 0 && itype != URL_LOCAL);
381 public static boolean isLocal(String fileName) {
382 if (fileName == null)
384 int itype = urlTypeIndex(fileName);
385 return (itype < 0 || itype == URL_LOCAL);
388 public static int urlTypeIndex(String name) {
390 return -2; // local unsigned applet
391 for (int i = 0; i < urlPrefixes.length; ++i) {
392 if (name.startsWith(urlPrefixes[i])) {
400 public void writeInt(int i) {
402 writeByteAsInt(i >> 24);
403 writeByteAsInt(i >> 16);
404 writeByteAsInt(i >> 8);
408 writeByteAsInt(i >> 8);
409 writeByteAsInt(i >> 16);
410 writeByteAsInt(i >> 24);
414 public void writeFloat(float x) {
415 writeInt(x == 0 ? 0 : Float.floatToIntBits(x));