Evolving Software

As everybody probably knows, Java only supports Big Endian streams but every once and a while you find yourself in the predicament of wanting to interface with a legacy system that wants to use little endian encoding. So I’m attaching a class that will allow you to use the nice DataInputStream API but that will read the data in little endian format.

*On a side note if you don’t know the difference between big and little endian or what the etymology of the term is. Endianess is basically to do start reading from the left most or right most bit (assuming bits were arranged in this fashion) you can find more information here. The term comes from Jonathan Swift’s satirical novel Gulliver’s Travels where there was a large disagreement about which side of one’s soft-boiled egg you should open.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
public class LittleEndianDataInputStream extends InputStream implements DataInput {
 
	public LittleEndianDataInputStream(InputStream in) {
		this.in = in;
		this.d = new DataInputStream(in);
		w = new byte[8];
	}
 
	public int available() throws IOException {
		return d.available();
	}
 
 
	public final short readShort() throws IOException
	{
		d.readFully(w, 0, 2);
		return (short)(
				(w[1]&0xff) << 8 |
				(w[0]&0xff));
	}
 
	/**
	 * Note, returns int even though it reads a short.
	 */
	 public final int readUnsignedShort() throws IOException
	 {
		 d.readFully(w, 0, 2);
		 return (
				 (w[1]&0xff) << 8 |
				 (w[0]&0xff));
	 }
 
	 /**
	  * like DataInputStream.readChar except little endian.
	  */
	 public final char readChar() throws IOException
	 {
		 d.readFully(w, 0, 2);
		 return (char) (
				 (w[1]&0xff) << 8 |
				 (w[0]&0xff));
	 }
 
	 /**
	  * like DataInputStream.readInt except little endian.
	  */
	 public final int readInt() throws IOException
	 {
		 d.readFully(w, 0, 4);
		 return
		 (w[3])      << 24 |
		 (w[2]&0xff) << 16 |
		 (w[1]&0xff) <<  8 |
		 (w[0]&0xff);
	 }
 
	 /**
	  * like DataInputStream.readLong except little endian.
	  */
	 public final long readLong() throws IOException
	 {
		 d.readFully(w, 0, 8);
		 return
		 (long)(w[7])      << 56 | 
		 (long)(w[6]&0xff) << 48 |
		 (long)(w[5]&0xff) << 40 |
		 (long)(w[4]&0xff) << 32 |
		 (long)(w[3]&0xff) << 24 |
		 (long)(w[2]&0xff) << 16 |
		 (long)(w[1]&0xff) <<  8 |
		 (long)(w[0]&0xff);
	 }
 
	 public final float readFloat() throws IOException {
		 return Float.intBitsToFloat(readInt());
	 }
 
	 public final double readDouble() throws IOException {
		 return Double.longBitsToDouble(readLong());
	 }
 
	 public final int read(byte b[], int off, int len) throws IOException {
		 return in.read(b, off, len);
	 }
 
	 public final void readFully(byte b[]) throws IOException {
		 d.readFully(b, 0, b.length);
	 }
 
	 public final void readFully(byte b[], int off, int len) throws IOException {
		 d.readFully(b, off, len);
	 }
 
	 public final int skipBytes(int n) throws IOException {
		 return d.skipBytes(n);
	 }
 
	 public final boolean readBoolean() throws IOException {
		 return d.readBoolean();
	 }
 
	 public final byte readByte() throws IOException {
		 return d.readByte();
	 }
 
	 public int read() throws IOException {
		 return in.read();
	 }
 
	 public final int readUnsignedByte() throws IOException {
		 return d.readUnsignedByte();
	 }
 
	 @Deprecated
	 public final String readLine() throws IOException {
		 return d.readLine();
	 }
 
	 public final String readUTF() throws IOException {
		 return d.readUTF();
	 }
 
	 public final void close() throws IOException {
		 d.close();
	 }
 
	 private DataInputStream d; // to get at high level readFully methods of
	 // DataInputStream
	 private InputStream in; // to get at the low-level read methods of
	 // InputStream
	 private byte w[]; // work array for buffering input
}

Download: LittleEndianDataInputStream.java

enjoy

15 thoughts on “Little Endian Input Stream

  1. Gary S.

    Thanks! I’m dealing with a file format that has both big-endian and little-endian entries. So I created a MultiEndianDataInputStream that extends DataInputStream and adds methods like readIntLittleEndian(), readDoubleLittleEndian(), etc. I borrowed bits of your code to save a lot of time. I really appreciate you posting it.

  2. Anh Vo

    Is there a corresponding class LittleEndianDataOutputStream.java for outputting Little Endian?

    Thanks,

    Anh Vo

  3. Pippo

    Hi, it has been really useful, thanks.

    But can you explain why did you used “& 0xff” on each byte?

    Thanks, Pippo

  4. Charlie

    this causes a IOException but this should be the correct way to read it, right?

    LittleEndianDataInputStream ie = new LittleEndianDataInputStream(new FileInputStream(“data/indexes.bin”));
    while ((i = ie.readInt()) != -1) { // throws IOException when done

    }

    C output:
    $ ./read indexes.bin
    0
    6336
    7864
    8192
    8256
    8264
    $

    Java output:
    0
    6336
    7864
    8192
    8256
    8264
    Exception in thread “main” java.io.EOFException
    at java.io.DataInputStream.readFully(DataInputStream.java:197)
    at reconstruction.read.LittleEndianDataInputStream.readInt(LittleEndianDataInputStream.java:61)
    at reconstruction.read.DataParser.(DataParser.java:28)
    at reconstruction.read.DataParser.main(DataParser.java:38)

  5. Johan du Plessis

    I have used this class to read a structured binary file. The integers are read correctly but the readChar gives me a Chinese character when it should give an H. The content of the binary file from a hex editor gives the following: As you can see the section 48 6f 6d 65 is Home in Ascii

    02 00 00 00 22 02 00 00 4b a9 c8 ff b2 2d 33 00
    00 00 00 00 04 00 00 00 48 6f 6d 65 00 00 00 00

Leave a Reply