|
10 | 10 | */ |
11 | 11 | package mt.edu.um.cf2.jgribx |
12 | 12 |
|
13 | | -import mt.edu.um.cf2.jgribx.Bytes2Number.bytesToFloat |
14 | | -import mt.edu.um.cf2.jgribx.Bytes2Number.bytesToInt |
15 | | -import mt.edu.um.cf2.jgribx.Bytes2Number.bytesToUint |
16 | 13 | import java.io.FilterInputStream |
17 | 14 | import java.io.IOException |
18 | 15 | import java.io.InputStream |
| 16 | +import java.nio.ByteBuffer |
| 17 | +import java.nio.ByteOrder |
19 | 18 | import kotlin.math.ceil |
| 19 | +import kotlin.math.pow |
20 | 20 |
|
21 | 21 | /** |
22 | 22 | * This class is an input stream wrapper that can read a specific number of bytes and bits from an input stream. |
@@ -112,52 +112,41 @@ class GribInputStream(inputStream: InputStream?, private val onRead: (Long) -> U |
112 | 112 | * @return the unsigned integer value corresponding to the byte array |
113 | 113 | * @throws IOException |
114 | 114 | */ |
115 | | - fun readUINT(nBytes: Int): Int { |
| 115 | + fun readUInt(nBytes: Int): Int { |
116 | 116 | val data = read(nBytes) |
117 | 117 | return bytesToUint(data) |
118 | 118 | } |
119 | 119 |
|
120 | | - fun readINT(nBytes: Int, format: Int): Int { |
121 | | - val data = read(nBytes) |
122 | | - return bytesToInt(data, format) |
| 120 | + fun readSMInt(bytes: Int = 1): Int { |
| 121 | + val data = read(bytes) |
| 122 | + val negative = data[0].toInt() and 0x80 == 0x80 |
| 123 | + data[0] = (data[0].toInt() and 0x7F).toByte() |
| 124 | + var value = bytesToUint(data) |
| 125 | + if (negative) value *= -1 |
| 126 | + return value |
123 | 127 | } |
124 | 128 |
|
125 | | - fun readFloat(nBytes: Int, format: Int): Float { |
126 | | - val data = read(nBytes) |
127 | | - return bytesToFloat(data, format) |
| 129 | + fun readLong(bytes: Int = 4): Long { |
| 130 | + val data = read(bytes) |
| 131 | + require(bytes <= Long.SIZE_BYTES) { "nBytes cannot be larger than ${Long.SIZE_BYTES} bytes" } |
| 132 | + var value = 0L |
| 133 | + repeat(bytes) { i -> |
| 134 | + value = value or (data[i].toLong() and 0xFF shl ((bytes - i - 1) * 8)) |
| 135 | + } |
| 136 | + return value |
128 | 137 | } |
129 | 138 |
|
130 | | - /** |
131 | | - * Read an unsigned 8 bit value. |
132 | | - * |
133 | | - * @return unsigned 8 bit value as integer |
134 | | - * @throws IOException |
135 | | - */ |
136 | | - fun readUI8(): Int { |
137 | | - val ui8 = `in`.read() |
138 | | - if (ui8 < 0) throw IOException("End of input.") |
139 | | - onRead(incrementByteCounters()) |
140 | | - return ui8 |
141 | | - } |
| 139 | + fun readFloatIEEE754(bytes: Int = 4) = ByteBuffer |
| 140 | + .wrap(read(bytes)) |
| 141 | + .order(ByteOrder.BIG_ENDIAN) |
| 142 | + .float |
142 | 143 |
|
143 | | - /** |
144 | | - * Read specific number of unsigned bytes from the input stream. |
145 | | - * |
146 | | - * @param length number of bytes to read and return as integers |
147 | | - * @return unsigned bytes as integer values |
148 | | - * @throws IOException |
149 | | - */ |
150 | | - fun readUI8(length: Int): IntArray { |
151 | | - val data = IntArray(length) |
152 | | - var read = 0 |
153 | | - var i = 0 |
154 | | - while (i < length && read >= 0) { |
155 | | - read = read() |
156 | | - data[i] = read |
157 | | - i++ |
158 | | - } |
159 | | - if (read < 0) throw IOException("End of input.") |
160 | | - return data |
| 144 | + fun readFloatIBM(): Float { |
| 145 | + val data = read(4) |
| 146 | + val sign = if (data[0].toInt() and 0x80 == 0x80) -1 else 1 |
| 147 | + val exponent: Int = (data[0].toInt() and 0x7F) - 64 |
| 148 | + val mantissa = bytesToUint(data.copyOfRange(1, 4)) |
| 149 | + return (sign * 16.0.pow((exponent - 6).toDouble()) * mantissa).toFloat() |
161 | 150 | } |
162 | 151 |
|
163 | 152 | /** |
@@ -185,6 +174,12 @@ class GribInputStream(inputStream: InputStream?, private val onRead: (Long) -> U |
185 | 174 | return value |
186 | 175 | } |
187 | 176 |
|
| 177 | + override fun read(b: ByteArray): Int { |
| 178 | + val read = super.read(b) |
| 179 | + onRead(incrementByteCounters(read)) |
| 180 | + return read |
| 181 | + } |
| 182 | + |
188 | 183 | override fun read(b: ByteArray, off: Int, len: Int): Int { |
189 | 184 | val i = super.read(b, off, len) |
190 | 185 | bitCounter += (len * 8).toLong() |
@@ -236,23 +231,19 @@ class GribInputStream(inputStream: InputStream?, private val onRead: (Long) -> U |
236 | 231 | } |
237 | 232 | } |
238 | 233 |
|
239 | | - /** |
240 | | - * Read a signed value from the given number of bits |
241 | | - * |
242 | | - * @param numBits number of bits used for the signed value |
243 | | - * @return value read from <tt>numBits</tt> bits as integer |
244 | | - * @throws IOException |
245 | | - */ |
246 | | - fun readSBits(numBits: Int): Int { |
247 | | - // Get the number as an unsigned value. |
248 | | - var uBits = readUBits(numBits) |
249 | | - |
250 | | - // Is the number negative? |
251 | | - if (uBits and (1L shl numBits - 1) != 0L) { |
| 234 | + fun readString(bytes: Int = 1): String { |
| 235 | + if (peekBuffer.size != bytes) peekBuffer = ByteArray(bytes) |
| 236 | + read(peekBuffer) |
| 237 | + return String(peekBuffer) |
| 238 | + } |
252 | 239 |
|
253 | | - // Yes. Extend the sign. |
254 | | - uBits = uBits or (-1L shl numBits) |
| 240 | + private fun bytesToUint(bytes: ByteArray): Int { |
| 241 | + val nBytes = bytes.size |
| 242 | + require(nBytes <= Int.SIZE_BYTES) { "nBytes cannot be larger than ${Int.SIZE_BYTES} bytes" } |
| 243 | + var value = 0 |
| 244 | + repeat(nBytes) { i -> |
| 245 | + value = value or (bytes[i].toInt() and 0xFF shl (nBytes - i - 1) * 8) |
255 | 246 | } |
256 | | - return uBits.toInt() |
| 247 | + return value |
257 | 248 | } |
258 | 249 | } |
0 commit comments