Skip to content

Commit 26feeca

Browse files
committed
Cleanup byte conversion helper
- simplify and move to Grib(Input/Output)Stream
1 parent 0d64acf commit 26feeca

26 files changed

+236
-420
lines changed

src/main/java/mt/edu/um/cf2/jgribx/Bytes2Number.kt

Lines changed: 0 additions & 190 deletions
This file was deleted.

src/main/java/mt/edu/um/cf2/jgribx/GribInputStream.kt

Lines changed: 47 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,13 @@
1010
*/
1111
package mt.edu.um.cf2.jgribx
1212

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
1613
import java.io.FilterInputStream
1714
import java.io.IOException
1815
import java.io.InputStream
16+
import java.nio.ByteBuffer
17+
import java.nio.ByteOrder
1918
import kotlin.math.ceil
19+
import kotlin.math.pow
2020

2121
/**
2222
* 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
112112
* @return the unsigned integer value corresponding to the byte array
113113
* @throws IOException
114114
*/
115-
fun readUINT(nBytes: Int): Int {
115+
fun readUInt(nBytes: Int): Int {
116116
val data = read(nBytes)
117117
return bytesToUint(data)
118118
}
119119

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
123127
}
124128

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
128137
}
129138

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
142143

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()
161150
}
162151

163152
/**
@@ -185,6 +174,12 @@ class GribInputStream(inputStream: InputStream?, private val onRead: (Long) -> U
185174
return value
186175
}
187176

177+
override fun read(b: ByteArray): Int {
178+
val read = super.read(b)
179+
onRead(incrementByteCounters(read))
180+
return read
181+
}
182+
188183
override fun read(b: ByteArray, off: Int, len: Int): Int {
189184
val i = super.read(b, off, len)
190185
bitCounter += (len * 8).toLong()
@@ -236,23 +231,19 @@ class GribInputStream(inputStream: InputStream?, private val onRead: (Long) -> U
236231
}
237232
}
238233

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+
}
252239

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)
255246
}
256-
return uBits.toInt()
247+
return value
257248
}
258249
}

src/main/java/mt/edu/um/cf2/jgribx/GribOutputStream.kt

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,15 +28,22 @@ class GribOutputStream(outputStream: OutputStream) : FilterOutputStream(outputSt
2828

2929
fun writeByte(value: Byte) = out.write(value.toInt())
3030

31-
fun writeUInt(value: Int, bytes: Int = 1) = out.write(Bytes2Number.uintToBytes(value, bytes))
31+
fun writeUInt(value: Int, bytes: Int = 1) = out.write(uintToBytes(value, bytes))
3232

3333
fun writeSMInt(value: Int, bytes: Int = 1) {
34-
val data = Bytes2Number.uintToBytes(abs(value), bytes)
34+
val data = uintToBytes(abs(value), bytes)
3535
data[0] = if (value < 0) data[0] or 0x80.toByte() else data[0] and 0x7F.toByte()
3636
out.write(data)
3737
}
3838

39-
fun writeLong(value: Long, bytes: Int = 1) = out.write(Bytes2Number.longToBytes(value, bytes))
39+
fun writeLong(value: Long, bytes: Int = 1) {
40+
require(bytes <= Long.SIZE_BYTES) { "nBytes cannot be larger than ${Long.SIZE_BYTES} bytes" }
41+
val data = ByteArray(bytes)
42+
repeat(bytes) { i ->
43+
data[i] = ((value shr ((bytes - i - 1) * 8)) and 0xFF).toByte()
44+
}
45+
out.write(data)
46+
}
4047

4148
fun writeFloatIEEE754(value: Float, bytes: Int = 4) {
4249
val data = ByteBuffer.allocate(bytes).order(ByteOrder.BIG_ENDIAN).putFloat(value).array()
@@ -93,4 +100,13 @@ class GribOutputStream(outputStream: OutputStream) : FilterOutputStream(outputSt
93100
bitsWritten = 0
94101
}
95102
}
103+
104+
private fun uintToBytes(value: Int, nBytes: Int = Int.SIZE_BYTES): ByteArray {
105+
require(nBytes <= Int.SIZE_BYTES) { "nBytes cannot be larger than ${Int.SIZE_BYTES} bytes" }
106+
val bytes = ByteArray(nBytes)
107+
repeat(nBytes) { i ->
108+
bytes[i] = ((value shr ((nBytes - i - 1) * 8)) and 0xFF).toByte()
109+
}
110+
return bytes
111+
}
96112
}

0 commit comments

Comments
 (0)