1 // Copyright (C) 2000, 2001, 2002, 2003 Philip Aston
2 // All rights reserved.
3 //
4 // This file is part of The Grinder software distribution. Refer to
5 // the file LICENSE which is part of The Grinder distribution for
6 // licensing details. The Grinder distribution is available on the
7 // Internet at http://grinder.sourceforge.net/
8 //
9 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
10 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
11 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
12 // FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
13 // COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
14 // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
15 // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
16 // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
17 // HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
18 // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
19 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
20 // OF THE POSSIBILITY OF SUCH DAMAGE.
21
22 package net.grinder.util;
23
24 import java.io.DataInput;
25 import java.io.DataOutput;
26 import java.io.IOException;
27
28
29 /**
30 * Utility methods for efficient serialisation.
31 *
32 * @author Philip Aston
33 */
34 public class Serialiser {
35
36 private final byte[] m_byteBuffer = new byte[8];
37
38 /**
39 * Write a <code>long</code> to a stream in such a way it can be
40 * read by {@link #readUnsignedLong}. The value of the
41 * <code>long</code> must be greater than zero. Values between 0 and
42 * 127 inclusive require only one byte. Other values require eight
43 * bytes.
44 *
45 * @param output The stream.
46 * @param l a <code>long</code> value
47 * @exception IOException If the stream raises an error.
48 */
49 public final void writeUnsignedLong(DataOutput output, long l)
50 throws IOException {
51
52 if (l < 0) {
53 throw new IOException("Negative argument");
54 }
55
56 if (l < 0x80) {
57 output.writeByte((byte)l);
58 }
59 else {
60 output.writeLong(-l);
61 }
62 }
63
64 /**
65 * Read a <code>long</code> written by {@link #writeUnsignedLong}.
66 *
67 * @param input The stream.
68 * @return The value.
69 * @exception IOException If the stream raises an error.
70 */
71 public final long readUnsignedLong(DataInput input) throws IOException {
72
73 m_byteBuffer[0] = input.readByte();
74
75 if (m_byteBuffer[0] >= 0) {
76 return m_byteBuffer[0];
77 }
78 else {
79 input.readFully(m_byteBuffer, 1, 7);
80
81 return -(((long)(m_byteBuffer[0] & 0xFF) << 56) |
82 ((long)(m_byteBuffer[1] & 0xFF) << 48) |
83 ((long)(m_byteBuffer[2] & 0xFF) << 40) |
84 ((long)(m_byteBuffer[3] & 0xFF) << 32) |
85 ((long)(m_byteBuffer[4] & 0xFF) << 24) |
86 ((long)(m_byteBuffer[5] & 0xFF) << 16) |
87 ((long)(m_byteBuffer[6] & 0xFF) << 8) |
88 ((long)(m_byteBuffer[7] & 0xFF) << 0));
89 }
90 }
91
92 /**
93 * Write a <code>long</code> to a stream in such a way it can be
94 * read by {@link #readLong}.
95 *
96 * <p>Efficient for small, positive longs. Values less than 16
97 * take one byte. The worst cases (including all negative values)
98 * take nine bytes.</p>
99 *
100 * @param output The stream.
101 * @param l Value to write.
102 * @exception IOException If the stream raises an error.
103 */
104 public final void writeLong(DataOutput output, long l)
105 throws IOException {
106
107 boolean startedToWrite = false;
108
109 for (byte i = (byte)(m_byteBuffer.length - 1); i >= 0; --i) {
110 final byte b = (byte)((l >>> i * 8) & 0xFF);
111
112 if (startedToWrite) {
113 output.writeByte(b);
114 }
115 else {
116 if ((b & 0xFF) != 0) {
117 if ((b & 0xF0) != 0) {
118 // Write length.
119 output.writeByte((i + 1) << 4);
120 output.writeByte(b);
121 }
122 else {
123 // Special case, byte will fit in one nibble.
124 // Combine with length.
125 output.writeByte(b | (i << 4));
126 }
127
128 startedToWrite = true;
129 }
130 }
131 }
132
133 if (!startedToWrite) {
134 output.writeByte(0);
135 }
136 }
137
138
139 /**
140 * Read a <code>long</code> written by {@link #writeLong}.
141 *
142 * @param input The stream.
143 * @return The value.
144 * @exception IOException If the stream raises an error.
145 */
146 public final long readLong(DataInput input) throws IOException {
147
148 final byte b = input.readByte();
149 long length = (b & 0xF0) >>> 4;
150 long result = b & 0x0F;
151
152 while (length-- > 0) {
153 result = (result << 8) | input.readUnsignedByte();
154 }
155
156 return result;
157 }
158
159 /**
160 * Write a <code>double</code> to a stream in such a way it can be
161 * read by {@link #readDouble}.
162 *
163 * @param output The stream.
164 * @param l The value.
165 * @throws IOException If the stream raises an error.
166 **/
167 public final void writeDouble(DataOutput output, double l)
168 throws IOException {
169
170 // One day we'll make this efficient again.
171 output.writeDouble(l);
172 }
173
174 /**
175 * Read a <code>double</code> written by {@link #writeDouble}.
176 *
177 * @param input The stream.
178 * @return The value.
179 * @throws IOException If the stream raises an error.
180 */
181 public final double readDouble(DataInput input) throws IOException {
182
183 return input.readDouble();
184 }
185 }