172ed7cf391c60ec86119f0b68b8f8c143f6d49b
[jalviewjs.git] / src / javajs / util / BinaryDocument.java
1 /* $RCSfile$
2  * $Author: egonw $
3  * $Date: 2006-03-18 15:59:33 -0600 (Sat, 18 Mar 2006) $
4  * $Revision: 4652 $
5  *
6  * Copyright (C) 2003-2005  Miguel, Jmol Development, www.jmol.org
7  *
8  * Contact: hansonr@stolaf.edu
9  *
10  *  This library is free software; you can redistribute it and/or
11  *  modify it under the terms of the GNU Lesser General Public
12  *  License as published by the Free Software Foundation; either
13  *  version 2.1 of the License, or (at your option) any later version.
14  *
15  *  This library is distributed in the hope that it will be useful,
16  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
17  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18  *  Lesser General Public License for more details.
19  *
20  *  You should have received a copy of the GNU Lesser General Public
21  *  License along with this library; if not, write to the Free Software
22  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
23  */
24 package javajs.util;
25
26
27 import java.io.BufferedInputStream;
28 import java.io.DataInputStream;
29 import java.util.Map;
30
31
32 import javajs.api.GenericBinaryDocument;
33 import javajs.api.GenericZipTools;
34
35
36 //import java.io.RandomAccessFile;
37
38 /* a basic binary file reader (extended by CompoundDocument). 
39  * 
40  * random access file info: 
41  * http://java.sun.com/docs/books/tutorial/essential/io/rafs.html
42  * 
43  * SHOOT! random access is only for applications, not applets!
44  * 
45  * Note that YOU are responsible for determining whether a file
46  * is bigEndian or littleEndian; the default is bigEndian.
47  * 
48  * JavaScript note: readShort() malfunctioned because (short) (xx << 8) 
49  * isn't the same as (int) (xx << 8); same problem in java.io.DataStream
50  * 
51  * 
52  */
53
54 public class BinaryDocument extends BC implements GenericBinaryDocument {
55
56   /**
57    * @j2sIgnore
58    */
59   public BinaryDocument() {  
60   }
61
62
63   // called by reflection
64   
65   protected DataInputStream stream;
66   protected boolean isRandom = false;
67   public boolean isBigEndian = true;
68   protected GenericZipTools jzt;
69
70   @Override
71   public void close() {
72     if (stream != null)
73       try {
74         stream.close();
75       } catch (Exception e) {
76         // ignore
77       }
78     if (out != null)
79        out.closeChannel();
80   }
81   
82   @Override
83   public void setStream(GenericZipTools jzt, BufferedInputStream bis, boolean isBigEndian) {
84     if (jzt != null)
85       this.jzt = jzt;
86     if (bis != null)
87       stream = new DataInputStream(bis);
88     this.isBigEndian = isBigEndian;
89   }
90   
91   @Override
92   public void setStreamData(DataInputStream stream, boolean isBigEndian) {
93     if (stream != null)
94       this.stream = stream;
95     this.isBigEndian = isBigEndian;
96   }
97   
98   public void setRandom(boolean TF) {
99     isRandom = TF;
100     //CANNOT be random for web 
101   }
102   
103   @Override
104   public byte readByte() throws Exception {
105     nBytes++;
106     return ioReadByte();
107   }
108
109   private byte ioReadByte() throws Exception {
110     byte b = stream.readByte();
111     if (out != null)
112       out.writeByteAsInt(b);
113     return b;
114   }
115
116   @Override
117   public int readByteArray(byte[] b, int off, int len) throws Exception {
118     int n = ioRead(b, off, len);
119     nBytes += n;
120     return n;
121   }
122
123   private int ioRead(byte[] b, int off, int len) throws Exception {
124     int m = 0;
125     while (len > 0) {
126       int n = stream.read(b, off, len);
127       m += n;
128       if (n > 0 && out != null)
129         writeBytes(b, off, n);
130       if (n >= len)
131         break;
132       off += n;
133       len -= n;
134     }
135     return m;
136   }
137
138   public void writeBytes(byte[] b, int off, int n) throws Exception {
139     out.write(b, off, n);
140   }
141
142   @Override
143   public String readString(int nChar) throws Exception {
144     byte[] temp = new byte[nChar];
145     int n = readByteArray(temp, 0, nChar);
146     return new String(temp, 0, n, "UTF-8");
147   }
148   
149   @Override
150   public short readShort() throws Exception {
151     nBytes += 2;
152     short n = (isBigEndian ? ioReadShort()
153         : (short) ((ioReadByte() & 0xff) 
154                  | (ioReadByte() & 0xff) << 8));
155     /**
156      * @j2sNative
157      *
158      * return (n > 0x7FFF ? n - 0x10000 : n);
159      */
160     {
161       return n;
162     }
163   }
164
165   private short ioReadShort() throws Exception {
166     short b = stream.readShort();
167     if (out != null)
168       writeShort(b);
169     return b;
170   }
171
172
173   public void writeShort(short i) throws Exception {
174     out.writeByteAsInt(i >> 8);
175     out.writeByteAsInt(i);
176   }
177
178   @Override
179   public int readIntLE() throws Exception {
180     nBytes += 4;
181     return readLEInt();
182   }
183   
184   @Override
185   public int readInt() throws Exception {
186     nBytes += 4;
187     return (isBigEndian ? ioReadInt() : readLEInt());
188   }
189   
190   private int ioReadInt() throws Exception {
191     int i = stream.readInt();
192     if (out != null)
193       writeInt(i);
194     return i;
195   }
196
197   public void writeInt(int i) throws Exception {
198     out.writeByteAsInt(i >> 24);
199     out.writeByteAsInt(i >> 16);
200     out.writeByteAsInt(i >> 8);
201     out.writeByteAsInt(i);
202   }
203
204   @Override
205   public int swapBytesI(int n) {
206     return (((n >> 24) & 0xff)
207         | ((n >> 16) & 0xff) << 8
208         | ((n >> 8) & 0xff) << 16 
209         | (n & 0xff) << 24);
210   }
211
212   @Override
213   public short swapBytesS(short n) {
214     return (short) ((((n >> 8) & 0xff)
215         | (n & 0xff) << 8));
216   }
217
218   
219   @Override
220   public int readUnsignedShort() throws Exception {
221     nBytes += 2;
222     int a = (ioReadByte() & 0xff);
223     int b = (ioReadByte() & 0xff);
224     return (isBigEndian ? (a << 8) + b : (b << 8) + a);
225   }
226   
227   @Override
228   public long readLong() throws Exception {
229     nBytes += 8;
230     return (isBigEndian ? ioReadLong()
231        : ((((long) ioReadByte()) & 0xff)
232         | (((long) ioReadByte()) & 0xff) << 8
233         | (((long) ioReadByte()) & 0xff) << 16
234         | (((long) ioReadByte()) & 0xff) << 24
235         | (((long) ioReadByte()) & 0xff) << 32
236         | (((long) ioReadByte()) & 0xff) << 40
237         | (((long) ioReadByte()) & 0xff) << 48 
238         | (((long) ioReadByte()) & 0xff) << 54));
239   }
240
241   private long ioReadLong() throws Exception {
242     long b = stream.readLong();
243     if (out != null)
244       writeLong(b);
245     return b;
246   }
247
248   public void writeLong(long b) throws Exception {
249     writeInt((int)((b >> 32) & 0xFFFFFFFFl));
250     writeInt((int)(b & 0xFFFFFFFFl));
251   }
252
253   private int readLEInt() throws Exception {
254     ioRead(t8, 0, 4);
255     return bytesToInt(t8, 0, false);
256   }
257
258   byte[] t8 = new byte[8];
259   
260   @Override
261   public float readFloat() throws Exception {
262     return intToFloat(readInt());
263   }
264
265   @Override
266   public double readDouble() throws Exception {
267     /**
268      * 
269      * reading the float equivalent here in JavaScript
270      * 
271      * @j2sNative
272      * 
273      * this.readByteArray(this.t8, 0, 8);
274      * return this.bytesToDoubleToFloat(this.t8, 0, this.isBigEndian);
275      *  
276      */
277     {
278       nBytes += 8;
279       return (isBigEndian ? ioReadDouble() : Double.longBitsToDouble(readLELong()));  
280     }
281   }
282   
283   private double ioReadDouble() throws Exception {
284     double d = stream.readDouble();
285     if (out != null)
286       writeLong(Double.doubleToRawLongBits(d));
287     return d;
288   }
289
290   private long readLELong() throws Exception {
291     return ((((long) ioReadByte()) & 0xff)
292           | (((long) ioReadByte()) & 0xff) << 8
293           | (((long) ioReadByte()) & 0xff) << 16 
294           | (((long) ioReadByte()) & 0xff) << 24
295           | (((long) ioReadByte()) & 0xff) << 32
296           | (((long) ioReadByte()) & 0xff) << 40
297           | (((long) ioReadByte()) & 0xff) << 48
298           | (((long) ioReadByte()) & 0xff) << 56);
299   }
300
301   @Override
302   public void seek(long offset) {
303     // slower, but all that is available using the applet
304     try {
305       if (offset == nBytes)
306         return;
307       if (offset < nBytes) {
308         stream.reset();
309         if (out != null && nBytes != 0)
310           out.reset();
311         nBytes = 0;
312       } else {
313         offset -= nBytes;
314       }
315       if (out == null) {
316         stream.skipBytes((int)offset);
317       } else {
318         readByteArray(new byte[(int)offset], 0, (int) offset);
319       }
320       nBytes += offset;
321     } catch (Exception e) {
322       System.out.println(e.toString());
323     }
324   }
325
326   long nBytes;
327   
328   @Override
329   public long getPosition() {
330     return nBytes;
331   }
332
333   OC out;
334   @Override
335   public void setOutputChannel(OC out) {
336       this.out = out;
337   }
338
339   @Override
340   public SB getAllDataFiles(String binaryFileList, String firstFile) {
341     return null;
342   }
343
344   @Override
345   public void getAllDataMapped(String replace, String string,
346                                Map<String, String> fileData) {
347   }
348
349
350 /*  random access -- application only:
351  * 
352     void seekFile(long offset) {
353     try {
354       file.seek(offset);
355     } catch (Exception e) {
356       System.out.println(e.getMessage());
357     }
358   }
359 */
360 }