vendor_boot: allow null bootconfig

pull/94/head
cfig 3 years ago
parent 5aad5d8793
commit 3ae5d567e3
No known key found for this signature in database
GPG Key ID: B104C307F0FDABB7

@ -14,7 +14,7 @@
package avb.alg
import cfig.io.Struct3
import cc.cfig.io.Struct3
class Algorithms {
companion object {

@ -17,7 +17,7 @@ package avb.blob
import avb.alg.Algorithms
import cfig.helper.CryptoHelper
import cfig.helper.Helper
import cfig.io.Struct3
import cc.cfig.io.Struct3
import org.slf4j.LoggerFactory
import java.nio.file.Files
import java.nio.file.Paths

@ -18,7 +18,7 @@ import avb.alg.Algorithm
import avb.desc.*
import cfig.helper.CryptoHelper
import cfig.helper.Helper
import cfig.io.Struct3
import cc.cfig.io.Struct3
import com.fasterxml.jackson.annotation.JsonIgnoreProperties
import org.bouncycastle.asn1.pkcs.RSAPrivateKey
import org.slf4j.LoggerFactory

@ -14,7 +14,7 @@
package avb.blob
import cfig.io.Struct3
import cc.cfig.io.Struct3
import java.io.File
import java.io.FileInputStream
import java.io.InputStream

@ -15,7 +15,7 @@
package avb.blob
import cfig.Avb
import cfig.io.Struct3
import cc.cfig.io.Struct3
import java.io.InputStream
//avbtool::AvbVBMetaHeader

@ -17,7 +17,7 @@ package avb.desc
import avb.AVBInfo
import cfig.Avb
import cfig.helper.Helper
import cfig.io.Struct3
import cc.cfig.io.Struct3
import java.io.File
import java.io.InputStream
import java.security.MessageDigest

@ -16,7 +16,7 @@ package avb.desc
import avb.blob.Header
import cfig.helper.Helper
import cfig.io.Struct3
import cc.cfig.io.Struct3
import org.apache.commons.codec.binary.Hex
import org.slf4j.LoggerFactory
import java.io.File

@ -17,7 +17,7 @@ package avb.desc
import avb.blob.Header
import cfig.helper.CryptoHelper
import cfig.helper.Helper
import cfig.io.Struct3
import cc.cfig.io.Struct3
import org.slf4j.LoggerFactory
import java.io.*
import java.security.MessageDigest

@ -15,7 +15,7 @@
package avb.desc
import cfig.helper.Helper
import cfig.io.Struct3
import cc.cfig.io.Struct3
import java.io.InputStream
class KernelCmdlineDescriptor(

@ -15,7 +15,7 @@
package avb.desc
import cfig.helper.Helper
import cfig.io.Struct3
import cc.cfig.io.Struct3
import java.io.InputStream
class PropertyDescriptor(

@ -14,8 +14,8 @@
package avb.desc
import cc.cfig.io.Struct3
import cfig.helper.Helper
import cfig.io.Struct3
import org.apache.commons.codec.binary.Hex
import org.slf4j.LoggerFactory
import java.io.ByteArrayInputStream

@ -14,7 +14,7 @@
package cfig.bcb
import cfig.io.Struct3
import cc.cfig.io.Struct3
import org.slf4j.LoggerFactory
import java.io.File
import java.io.FileInputStream

@ -14,7 +14,7 @@
package cfig.bcb
import cfig.io.Struct3
import cc.cfig.io.Struct3
import org.slf4j.LoggerFactory
import java.io.FileInputStream

@ -14,8 +14,8 @@
package cfig.bcb
import cc.cfig.io.Struct3
import cfig.helper.Helper
import cfig.io.Struct3
import org.slf4j.LoggerFactory
import java.io.FileInputStream

@ -14,12 +14,12 @@
package cfig.bootimg
import cc.cfig.io.Struct3
import cfig.utils.EnvironmentVerifier
import cfig.bootimg.cpio.AndroidCpio
import cfig.utils.DTC
import cfig.helper.Helper
import cfig.helper.ZipHelper
import cfig.io.Struct3
import cfig.utils.KernelExtractor
import org.apache.commons.exec.CommandLine
import org.apache.commons.exec.DefaultExecutor
@ -66,9 +66,9 @@ class Common {
if (m.groupCount() == 3) {
c = Integer.decode(m.group(3))
}
assert(a < 128)
assert(b < 128)
assert(c < 128)
check(a < 128)
check(b < 128)
check(c < 128)
return (a shl 14) or (b shl 7) or c
} else {
throw IllegalArgumentException("invalid os_version")
@ -91,8 +91,8 @@ class Common {
val y = Integer.parseInt(matcher.group(1), 10) - 2000
val m = Integer.parseInt(matcher.group(2), 10)
// 7 bits allocated for the year, 4 bits for the month
assert(y in 0..127)
assert(m in 1..12)
check(y in 0..127)
check(m in 1..12)
ret = (y shl 4) or m
} else {
throw IllegalArgumentException("invalid os_patch_level")
@ -307,7 +307,7 @@ class Common {
fun writePaddedFile(inBF: ByteBuffer, srcFile: String, padding: UInt) {
log.info("adding $srcFile into buffer ...")
assert(padding < Int.MAX_VALUE.toUInt())
check(padding < Int.MAX_VALUE.toUInt())
writePaddedFile(inBF, srcFile, padding.toInt())
}

@ -14,7 +14,7 @@
package cfig.bootimg.cpio
import cfig.io.Struct3
import cc.cfig.io.Struct3
import org.apache.commons.compress.archivers.cpio.CpioConstants
import java.util.*

@ -14,9 +14,9 @@
package cfig.bootimg.v2
import cc.cfig.io.Struct3
import cfig.helper.Helper
import cfig.bootimg.Common
import cfig.io.Struct3
import org.slf4j.LoggerFactory
import java.io.InputStream
import kotlin.math.pow

@ -14,8 +14,8 @@
package cfig.bootimg.v3
import cc.cfig.io.Struct3
import cfig.bootimg.Common
import cfig.io.Struct3
import org.slf4j.LoggerFactory
import java.io.InputStream

@ -15,12 +15,12 @@
package cfig.bootimg.v3
import avb.AVBInfo
import cc.cfig.io.Struct3
import cfig.Avb
import cfig.utils.EnvironmentVerifier
import cfig.bootimg.Common.Companion.deleleIfExists
import cfig.bootimg.Signer
import cfig.helper.Helper
import cfig.io.Struct3
import cfig.packable.VBMetaParser
import com.fasterxml.jackson.databind.ObjectMapper
import de.vandermeer.asciitable.AsciiTable
@ -287,7 +287,9 @@ data class VendorBoot(
//2. vrt
it.put(this.ramdisk_table.update().encode(this.info.pageSize))
//3. bootconfig
C.writePaddedFile(it, this.bootconfig.file, this.info.pageSize)
if (this.bootconfig.file.isNotBlank()) {
C.writePaddedFile(it, this.bootconfig.file, this.info.pageSize)
}
it
}
}
@ -451,7 +453,9 @@ data class VendorBoot(
addArgument("--ramdisk_name").addArgument(it.name, true)
addArgument("--vendor_ramdisk_fragment").addArgument(it.file)
}
addArgument("--vendor_bootconfig").addArgument(bootconfig.file)
if (bootconfig.file.isNotBlank()) {
addArgument("--vendor_bootconfig").addArgument(bootconfig.file)
}
}
}
addArgument("--dtb").addArgument(dtb.file)

@ -14,7 +14,7 @@
package cfig.bootimg.v3
import cfig.io.Struct3
import cc.cfig.io.Struct3
import org.slf4j.LoggerFactory
import java.io.InputStream

@ -1,12 +1,12 @@
package utils
import avb.AVBInfo
import cc.cfig.io.Struct3
import cfig.Avb
import cfig.bootimg.Common
import cfig.bootimg.Signer
import cfig.bootimg.v3.VendorBoot
import cfig.helper.Helper
import cfig.io.Struct3
import cfig.packable.VBMetaParser
import cfig.utils.DTC
import com.fasterxml.jackson.databind.ObjectMapper

@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.3-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

@ -1,6 +1,7 @@
@file:Suppress("JAVA_MODULE_DOES_NOT_EXPORT_PACKAGE")
package cfig.helper
import cfig.io.Struct3
import cc.cfig.io.Struct3
import com.google.common.math.BigIntegerMath
import org.apache.commons.exec.CommandLine
import org.apache.commons.exec.DefaultExecutor

@ -14,7 +14,7 @@
package cfig.helper
import cfig.io.Struct3
import cc.cfig.io.Struct3
import org.apache.commons.exec.CommandLine
import org.apache.commons.exec.DefaultExecutor
import org.apache.commons.exec.ExecuteException

@ -14,9 +14,9 @@
package cfig.helper
import cc.cfig.io.Struct3
import cfig.helper.Helper.Companion.check_call
import cfig.helper.Helper.Companion.check_output
import cfig.io.Struct3
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry
import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream
import org.apache.commons.compress.archivers.zip.ZipArchiveInputStream

@ -1,7 +1,19 @@
package cfig.io
// Copyright 2022 yuyezhong@gmail.com
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package cc.cfig.io
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import java.io.IOException
import java.io.InputStream
import java.nio.ByteBuffer
@ -72,7 +84,7 @@ class Struct3(inFormatString: String) {
return ByteBuffer.allocate(this.calcSize()).let { bf ->
bf.order(this.byteOrder)
args.forEachIndexed { index, arg ->
warships.get(index).put(bf, arg)
warships[index].put(bf, arg)
}
bf.array()
}
@ -86,7 +98,6 @@ class Struct3(inFormatString: String) {
private interface IWarShip<T> {
val sz: Int
var multiple: Int
val log: Logger
fun get(stream: InputStream, byteOrder: ByteOrder): T
fun get(ba: ByteArray, byteOrder: ByteOrder): T
fun put(bf: ByteBuffer, arg: Any?)
@ -112,7 +123,7 @@ class Struct3(inFormatString: String) {
it.order(byteOrder)
it.put(ba)
it.flip()
it.getShort()
it.short
}
}
@ -133,7 +144,6 @@ class Struct3(inFormatString: String) {
}
override val sz: Int = Short.SIZE_BYTES
override val log: Logger = LoggerFactory.getLogger(ShortShip::class.java)
}
private class UShortShip : IBaseShip<UShort> {
@ -150,7 +160,7 @@ class Struct3(inFormatString: String) {
it.order(byteOrder)
it.put(ba)
it.flip()
it.getShort().toUShort()
it.short.toUShort()
}
}
@ -175,7 +185,6 @@ class Struct3(inFormatString: String) {
}
override val sz: Int = UShort.SIZE_BYTES
override val log: Logger = LoggerFactory.getLogger(UShortShip::class.java)
}
//i, l: Int
@ -193,7 +202,7 @@ class Struct3(inFormatString: String) {
it.order(byteOrder)
it.put(ba)
it.flip()
it.getInt()
it.int
}
}
@ -207,7 +216,6 @@ class Struct3(inFormatString: String) {
}
override val sz: Int = Int.SIZE_BYTES
override val log: Logger = LoggerFactory.getLogger(IntShip::class.java)
}
//I, L: UInt
@ -225,7 +233,7 @@ class Struct3(inFormatString: String) {
it.order(byteOrder)
it.put(ba)
it.flip()
it.getInt().toUInt()
it.int.toUInt()
}
}
@ -249,7 +257,6 @@ class Struct3(inFormatString: String) {
}
override val sz: Int = UInt.SIZE_BYTES
override val log: Logger = LoggerFactory.getLogger(UIntShip::class.java)
}
//q: Long
@ -267,7 +274,7 @@ class Struct3(inFormatString: String) {
it.order(byteOrder)
it.put(ba)
it.flip()
it.getLong()
it.long
}
}
@ -284,7 +291,6 @@ class Struct3(inFormatString: String) {
}
override val sz: Int = Long.SIZE_BYTES
override val log: Logger = LoggerFactory.getLogger(LongShip::class.java)
}
//Q: ULong
@ -302,7 +308,7 @@ class Struct3(inFormatString: String) {
it.order(byteOrder)
it.put(ba)
it.flip()
it.getLong().toULong()
it.long.toULong()
}
}
@ -326,7 +332,6 @@ class Struct3(inFormatString: String) {
}
override val sz: Int = ULong.SIZE_BYTES
override val log: Logger = LoggerFactory.getLogger(ULongShip::class.java)
}
//c: character
@ -338,7 +343,7 @@ class Struct3(inFormatString: String) {
}
override fun get(ba: ByteArray, byteOrder: ByteOrder): Char {
return ba.get(0).toInt().toChar()
return ba[0].toInt().toChar()
}
override fun put(bf: ByteBuffer, arg: Any?) {
@ -354,21 +359,20 @@ class Struct3(inFormatString: String) {
}
override val sz: Int = 1
override val log: Logger = LoggerFactory.getLogger(CharShip::class.java)
}
private interface IBaseFleet<T> : IWarShip<T> {
fun appendPadding(bf: ByteBuffer, b: Byte, bufSize: Int) {
when {
bufSize == 0 -> {
log.debug("paddingSize is zero, perfect match")
//"paddingSize is zero, perfect match"
return
}
bufSize < 0 -> {
throw IllegalArgumentException("illegal padding size: $bufSize")
}
else -> {
log.debug("paddingSize $bufSize")
//"paddingSize $bufSize"
}
}
val padding = ByteArray(bufSize)
@ -382,9 +386,8 @@ class Struct3(inFormatString: String) {
if (paddingSize < 0) throw IllegalArgumentException("arg length [${inByteArray.size}] exceeds limit: $bufSize")
//data
bf.put(inByteArray)
//padding
//padding: "paddingSize $paddingSize"
appendPadding(bf, 0.toByte(), paddingSize)
log.debug("paddingSize $paddingSize")
}
fun appendByteArray(bf: ByteBuffer, inIntArray: IntArray, bufSize: Int) {
@ -429,7 +432,7 @@ class Struct3(inFormatString: String) {
}
override fun get(ba: ByteArray, byteOrder: ByteOrder): Byte {
TODO("Not yet implemented")
return ba[0]
}
override fun put(bf: ByteBuffer, arg: Any?) {
@ -444,8 +447,6 @@ class Struct3(inFormatString: String) {
override fun toString(): String {
return "${multiple}x"
}
override val log: Logger = LoggerFactory.getLogger(PaddingFleet::class.java)
}
//b: byte array
@ -457,7 +458,8 @@ class Struct3(inFormatString: String) {
}
override fun get(ba: ByteArray, byteOrder: ByteOrder): ByteArray {
TODO("Not yet implemented")
check(multiple == ba.size)
return ba
}
override fun put(bf: ByteBuffer, arg: Any?) {
@ -473,7 +475,6 @@ class Struct3(inFormatString: String) {
}
override val sz: Int = Byte.SIZE_BYTES
override val log: Logger = LoggerFactory.getLogger(ByteFleet::class.java)
}
//B: UByte array
@ -486,6 +487,10 @@ class Struct3(inFormatString: String) {
return innerData2.toUByteArray()
}
override fun get(ba: ByteArray, byteOrder: ByteOrder): UByteArray {
return ba.toUByteArray()
}
override fun put(bf: ByteBuffer, arg: Any?) {
when (arg) {
is ByteArray -> appendByteArray(bf, arg, multiple)
@ -501,12 +506,6 @@ class Struct3(inFormatString: String) {
override val sz: Int
get() = UByte.SIZE_BYTES
override fun get(ba: ByteArray, byteOrder: ByteOrder): UByteArray {
TODO("Not yet implemented")
}
override val log: Logger = LoggerFactory.getLogger(UByteFleet::class.java)
}
//s: String
@ -536,6 +535,5 @@ class Struct3(inFormatString: String) {
}
override val sz: Int = 1
override val log: Logger = LoggerFactory.getLogger(StringFleet::class.java)
}
}

@ -1,530 +0,0 @@
// Copyright 2021 yuyezhong@gmail.com
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package cfig.io
import cfig.io.Struct3Retire.ByteArrayExt.Companion.toCString
import cfig.io.Struct3Retire.ByteArrayExt.Companion.toInt
import cfig.io.Struct3Retire.ByteArrayExt.Companion.toLong
import cfig.io.Struct3Retire.ByteArrayExt.Companion.toShort
import cfig.io.Struct3Retire.ByteArrayExt.Companion.toUInt
import cfig.io.Struct3Retire.ByteArrayExt.Companion.toULong
import cfig.io.Struct3Retire.ByteArrayExt.Companion.toUShort
import cfig.io.Struct3Retire.ByteBufferExt.Companion.appendByteArray
import cfig.io.Struct3Retire.ByteBufferExt.Companion.appendPadding
import cfig.io.Struct3Retire.ByteBufferExt.Companion.appendUByteArray
import cfig.io.Struct3Retire.InputStreamExt.Companion.getByteArray
import cfig.io.Struct3Retire.InputStreamExt.Companion.getCString
import cfig.io.Struct3Retire.InputStreamExt.Companion.getChar
import cfig.io.Struct3Retire.InputStreamExt.Companion.getInt
import cfig.io.Struct3Retire.InputStreamExt.Companion.getLong
import cfig.io.Struct3Retire.InputStreamExt.Companion.getPadding
import cfig.io.Struct3Retire.InputStreamExt.Companion.getShort
import cfig.io.Struct3Retire.InputStreamExt.Companion.getUByteArray
import cfig.io.Struct3Retire.InputStreamExt.Companion.getUInt
import cfig.io.Struct3Retire.InputStreamExt.Companion.getULong
import cfig.io.Struct3Retire.InputStreamExt.Companion.getUShort
import org.slf4j.LoggerFactory
import java.io.IOException
import java.io.InputStream
import java.nio.ByteBuffer
import java.nio.ByteOrder
import java.nio.charset.StandardCharsets
import java.util.*
import java.util.regex.Pattern
import kotlin.random.Random
class Struct3Retire {
private val formatString: String
private var byteOrder = ByteOrder.LITTLE_ENDIAN
private val formats = ArrayList<Array<Any?>>()
constructor(inFormatString: String) {
assert(inFormatString.isNotEmpty()) { "FORMAT_STRING must not be empty" }
formatString = inFormatString
val m = Pattern.compile("(\\d*)([a-zA-Z])").matcher(formatString)
when (formatString[0]) {
'>', '!' -> this.byteOrder = ByteOrder.BIG_ENDIAN
'@', '=' -> this.byteOrder = ByteOrder.nativeOrder()
else -> this.byteOrder = ByteOrder.LITTLE_ENDIAN
}
while (m.find()) {
//item[0]: Type, item[1]: multiple
// if need to expand format items, explode it
// eg: "4L" will be exploded to "1L 1L 1L 1L", so it's treated as primitive
// eg: "10x" won't be exploded, it's still "10x", so it's treated as non-primitive
val typeName: Any = when (m.group(2)) {
//primitive types
"x" -> Random //byte 1 (exploded)
"b" -> Byte //byte 1 (exploded)
"B" -> UByte //UByte 1 (exploded)
"s" -> String //string (exploded)
//zippable types, which need to be exploded with multiple=1
"c" -> Char
"h" -> Short //2
"H" -> UShort //2
"i", "l" -> Int //4
"I", "L" -> UInt //4
"q" -> Long //8
"Q" -> ULong //8
else -> throw IllegalArgumentException("type [" + m.group(2) + "] not supported")
}
val bPrimitive = m.group(2) in listOf("x", "b", "B", "s")
val multiple = if (m.group(1).isEmpty()) 1 else Integer.decode(m.group(1))
if (bPrimitive) {
formats.add(arrayOf<Any?>(typeName, multiple))
} else {
for (i in 0 until multiple) {
formats.add(arrayOf<Any?>(typeName, 1))
}
}
}
}
private fun getFormatInfo(inCursor: Int): String {
return ("type=" + formats.get(inCursor)[0] + ", value=" + formats.get(inCursor)[1])
}
override fun toString(): String {
val formatStr = mutableListOf<String>()
formats.forEach {
val fs = StringBuilder()
when (it[0]) {
Random -> fs.append("x")
Byte -> fs.append("b")
UByte -> fs.append("B")
String -> fs.append("s")
Char -> fs.append("c")
Short -> fs.append("h")
UShort -> fs.append("H")
Int -> fs.append("i")
UInt -> fs.append("I")
Long -> fs.append("q")
ULong -> fs.append("Q")
else -> throw IllegalArgumentException("type [" + it[0] + "] not supported")
}
fs.append(":" + it[1])
formatStr.add(fs.toString())
}
return "Struct3Retire(formatString='$formatString', byteOrder=$byteOrder, formats=$formatStr)"
}
fun calcSize(): Int {
var ret = 0
for (format in formats) {
ret += when (val formatType = format[0]) {
Random, Byte, UByte, Char, String -> format[1] as Int
Short, UShort -> 2 * format[1] as Int
Int, UInt -> 4 * format[1] as Int
Long, ULong -> 8 * format[1] as Int
else -> throw IllegalArgumentException("Class [$formatType] not supported")
}
}
return ret
}
@Throws(IllegalArgumentException::class)
fun pack(vararg args: Any?): ByteArray {
if (args.size != this.formats.size) {
throw IllegalArgumentException("argument size " + args.size + " doesn't match format size " + this.formats.size)
}
val bf = ByteBuffer.allocate(this.calcSize())
bf.order(this.byteOrder)
for (i in args.indices) {
val arg = args[i]
val typeName = formats[i][0]
val multiple = formats[i][1] as Int
if (typeName !in arrayOf(Random, Byte, String, UByte)) {
assert(1 == multiple)
}
//x: padding:
if (Random == typeName) {
when (arg) {
null -> bf.appendPadding(0, multiple)
is Byte -> bf.appendPadding(arg, multiple)
is Int -> bf.appendPadding(arg.toByte(), multiple)
else -> throw IllegalArgumentException("Index[" + i + "] Unsupported arg [" + arg + "] with type [" + formats[i][0] + "]")
}
continue
}
//c: character
if (Char == typeName) {
assert(arg is Char) { "[$arg](${arg!!::class.java}) is NOT Char" }
if ((arg as Char) !in '\u0000'..'\u00ff') {
throw IllegalArgumentException("arg[${arg.code}] exceeds 8-bit bound")
}
bf.put(arg.code.toByte())
continue
}
//b: byte array
if (Byte == typeName) {
when (arg) {
is IntArray -> bf.appendByteArray(arg, multiple)
is ByteArray -> bf.appendByteArray(arg, multiple)
else -> throw IllegalArgumentException("[$arg](${arg!!::class.java}) is NOT ByteArray/IntArray")
}
continue
}
//B: UByte array
if (UByte == typeName) {
when (arg) {
is ByteArray -> bf.appendByteArray(arg, multiple)
is UByteArray -> bf.appendUByteArray(arg, multiple)
is IntArray -> bf.appendUByteArray(arg, multiple)
else -> throw IllegalArgumentException("[$arg](${arg!!::class.java}) is NOT ByteArray/IntArray")
}
continue
}
//s: String
if (String == typeName) {
assert(arg != null) { "arg can not be NULL for String, formatString=$formatString, ${getFormatInfo(i)}" }
assert(arg is String) { "[$arg](${arg!!::class.java}) is NOT String, ${getFormatInfo(i)}" }
bf.appendByteArray((arg as String).toByteArray(), multiple)
continue
}
//h: Short
if (Short == typeName) {
when (arg) {
is Int -> {
assert(arg in Short.MIN_VALUE..Short.MAX_VALUE) { "[$arg] is truncated as type Short.class" }
bf.putShort(arg.toShort())
}
is Short -> bf.putShort(arg) //instance Short
else -> throw IllegalArgumentException("[$arg](${arg!!::class.java}) is NOT Short/Int")
}
continue
}
//H: UShort
if (UShort == typeName) {
assert(arg is UShort || arg is UInt || arg is Int) { "[$arg](${arg!!::class.java}) is NOT UShort/UInt/Int" }
when (arg) {
is Int -> {
assert(arg >= UShort.MIN_VALUE.toInt() && arg <= UShort.MAX_VALUE.toInt()) { "[$arg] is truncated as type UShort" }
bf.putShort(arg.toShort())
}
is UInt -> {
assert(arg >= UShort.MIN_VALUE && arg <= UShort.MAX_VALUE) { "[$arg] is truncated as type UShort" }
bf.putShort(arg.toShort())
}
is UShort -> bf.putShort(arg.toShort())
}
continue
}
//i, l: Int
if (Int == typeName) {
assert(arg is Int) { "[$arg](${arg!!::class.java}) is NOT Int" }
bf.putInt(arg as Int)
continue
}
//I, L: UInt
if (UInt == typeName) {
when (arg) {
is Int -> {
assert(arg >= 0) { "[$arg] is invalid as type UInt" }
bf.putInt(arg)
}
is UInt -> bf.putInt(arg.toInt())
is Long -> {
assert(arg >= 0) { "[$arg] is invalid as type UInt" }
bf.putInt(arg.toInt())
}
else -> throw IllegalArgumentException("[$arg](${arg!!::class.java}) is NOT UInt/Int/Long")
}
continue
}
//q: Long
if (Long == typeName) {
when (arg) {
is Long -> bf.putLong(arg)
is Int -> bf.putLong(arg.toLong())
else -> throw IllegalArgumentException("[$arg](${arg!!::class.java}) is NOT Long/Int")
}
continue
}
//Q: ULong
if (ULong == typeName) {
when (arg) {
is Int -> {
assert(arg >= 0) { "[$arg] is invalid as type ULong" }
bf.putLong(arg.toLong())
}
is Long -> {
assert(arg >= 0) { "[$arg] is invalid as type ULong" }
bf.putLong(arg)
}
is ULong -> bf.putLong(arg.toLong())
else -> throw IllegalArgumentException("[$arg](${arg!!::class.java}) is NOT Int/Long/ULong")
}
continue
}
throw IllegalArgumentException("unrecognized format $typeName")
}
return bf.array()
}
@Throws(IOException::class, IllegalArgumentException::class)
fun unpack(iS: InputStream): List<*> {
val ret = ArrayList<Any>()
for (format in this.formats) {
when (format[0]) {
Random -> ret.add(iS.getPadding(format[1] as Int)) //return padding byte
Byte -> ret.add(iS.getByteArray(format[1] as Int)) //b: byte array
UByte -> ret.add(iS.getUByteArray(format[1] as Int)) //B: ubyte array
Char -> ret.add(iS.getChar()) //char: 1
String -> ret.add(iS.getCString(format[1] as Int)) //c string
Short -> ret.add(iS.getShort(this.byteOrder)) //h: short
UShort -> ret.add(iS.getUShort(this.byteOrder)) //H: UShort
Int -> ret.add(iS.getInt(this.byteOrder)) //i, l: Int
UInt -> ret.add(iS.getUInt(this.byteOrder)) //I, L: UInt
Long -> ret.add(iS.getLong(this.byteOrder)) //q: Long
ULong -> ret.add(iS.getULong(this.byteOrder)) //Q: ULong
else -> throw IllegalArgumentException("Class [" + format[0] + "] not supported")
}//end-of-when
}//end-of-for
return ret
}
class ByteBufferExt {
companion object {
private val log = LoggerFactory.getLogger(ByteBufferExt::class.java)
@Throws(IllegalArgumentException::class)
fun ByteBuffer.appendPadding(b: Byte, bufSize: Int) {
when {
bufSize == 0 -> {
log.debug("paddingSize is zero, perfect match")
return
}
bufSize < 0 -> {
throw IllegalArgumentException("illegal padding size: $bufSize")
}
else -> {
log.debug("paddingSize $bufSize")
}
}
val padding = ByteArray(bufSize)
Arrays.fill(padding, b)
this.put(padding)
}
fun ByteBuffer.appendByteArray(inIntArray: IntArray, bufSize: Int) {
val arg2 = mutableListOf<Byte>()
inIntArray.toMutableList().mapTo(arg2) {
if (it in Byte.MIN_VALUE..Byte.MAX_VALUE) {
it.toByte()
} else {
throw IllegalArgumentException("$it is not valid Byte")
}
}
appendByteArray(arg2.toByteArray(), bufSize)
}
@Throws(IllegalArgumentException::class)
fun ByteBuffer.appendByteArray(inByteArray: ByteArray, bufSize: Int) {
val paddingSize = bufSize - inByteArray.size
if (paddingSize < 0) throw IllegalArgumentException("arg length [${inByteArray.size}] exceeds limit: $bufSize")
//data
this.put(inByteArray)
//padding
this.appendPadding(0.toByte(), paddingSize)
log.debug("paddingSize $paddingSize")
}
fun ByteBuffer.appendUByteArray(inIntArray: IntArray, bufSize: Int) {
val arg2 = mutableListOf<UByte>()
inIntArray.toMutableList().mapTo(arg2) {
if (it in UByte.MIN_VALUE.toInt()..UByte.MAX_VALUE.toInt())
it.toUByte()
else {
throw IllegalArgumentException("$it is not valid Byte")
}
}
appendUByteArray(arg2.toUByteArray(), bufSize)
}
fun ByteBuffer.appendUByteArray(inUByteArray: UByteArray, bufSize: Int) {
val bl = mutableListOf<Byte>()
inUByteArray.toMutableList().mapTo(bl) { it.toByte() }
this.appendByteArray(bl.toByteArray(), bufSize)
}
}
}
private class InputStreamExt {
companion object {
fun InputStream.getChar(): Char {
val data = ByteArray(Byte.SIZE_BYTES)
assert(Byte.SIZE_BYTES == this.read(data))
return data[0].toInt().toChar()
}
fun InputStream.getShort(inByteOrder: ByteOrder): Short {
val data = ByteArray(Short.SIZE_BYTES)
assert(Short.SIZE_BYTES == this.read(data))
return data.toShort(inByteOrder)
}
fun InputStream.getInt(inByteOrder: ByteOrder): Int {
val data = ByteArray(Int.SIZE_BYTES)
assert(Int.SIZE_BYTES == this.read(data))
return data.toInt(inByteOrder)
}
fun InputStream.getLong(inByteOrder: ByteOrder): Long {
val data = ByteArray(Long.SIZE_BYTES)
assert(Long.SIZE_BYTES == this.read(data))
return data.toLong(inByteOrder)
}
fun InputStream.getUShort(inByteOrder: ByteOrder): UShort {
val data = ByteArray(UShort.SIZE_BYTES)
assert(UShort.SIZE_BYTES == this.read(data))
return data.toUShort(inByteOrder)
}
fun InputStream.getUInt(inByteOrder: ByteOrder): UInt {
val data = ByteArray(UInt.SIZE_BYTES)
assert(UInt.SIZE_BYTES == this.read(data))
return data.toUInt(inByteOrder)
}
fun InputStream.getULong(inByteOrder: ByteOrder): ULong {
val data = ByteArray(ULong.SIZE_BYTES)
assert(ULong.SIZE_BYTES == this.read(data))
return data.toULong(inByteOrder)
}
fun InputStream.getByteArray(inSize: Int): ByteArray {
val data = ByteArray(inSize)
assert(inSize == this.read(data))
return data
}
fun InputStream.getUByteArray(inSize: Int): UByteArray {
val data = ByteArray(inSize)
assert(inSize == this.read(data))
val innerData2 = mutableListOf<UByte>()
data.toMutableList().mapTo(innerData2) { it.toUByte() }
return innerData2.toUByteArray()
}
fun InputStream.getCString(inSize: Int): String {
val data = ByteArray(inSize)
assert(inSize == this.read(data))
return data.toCString()
}
fun InputStream.getPadding(inSize: Int): Byte {
val data = ByteArray(Byte.SIZE_BYTES)
assert(Byte.SIZE_BYTES == this.read(data)) //sample the 1st byte
val skipped = this.skip(inSize.toLong() - Byte.SIZE_BYTES)//skip remaining to save memory
assert(inSize.toLong() - Byte.SIZE_BYTES == skipped)
return data[0]
}
}
}
class ByteArrayExt {
companion object {
fun ByteArray.toShort(inByteOrder: ByteOrder): Short {
val typeSize = Short.SIZE_BYTES / Byte.SIZE_BYTES
assert(typeSize == this.size) { "Short must have $typeSize bytes" }
return ByteBuffer.allocate(this.size).let {
it.order(inByteOrder)
it.put(this)
it.flip()
it.getShort()
}
}
fun ByteArray.toInt(inByteOrder: ByteOrder): Int {
val typeSize = Int.SIZE_BYTES / Byte.SIZE_BYTES
assert(typeSize == this.size) { "Int must have $typeSize bytes" }
return ByteBuffer.allocate(this.size).let {
it.order(inByteOrder)
it.put(this)
it.flip()
it.getInt()
}
}
fun ByteArray.toLong(inByteOrder: ByteOrder): Long {
val typeSize = Long.SIZE_BYTES / Byte.SIZE_BYTES
assert(typeSize == this.size) { "Long must have $typeSize bytes" }
return ByteBuffer.allocate(this.size).let {
it.order(inByteOrder)
it.put(this)
it.flip()
it.getLong()
}
}
fun ByteArray.toUShort(inByteOrder: ByteOrder): UShort {
val typeSize = UShort.SIZE_BYTES / Byte.SIZE_BYTES
assert(typeSize == this.size) { "UShort must have $typeSize bytes" }
return ByteBuffer.allocate(this.size).let {
it.order(inByteOrder)
it.put(this)
it.flip()
it.getShort().toUShort()
}
}
fun ByteArray.toUInt(inByteOrder: ByteOrder): UInt {
val typeSize = UInt.SIZE_BYTES / Byte.SIZE_BYTES
assert(typeSize == this.size) { "UInt must have $typeSize bytes" }
return ByteBuffer.allocate(this.size).let {
it.order(inByteOrder)
it.put(this)
it.flip()
it.getInt().toUInt()
}
}
fun ByteArray.toULong(inByteOrder: ByteOrder): ULong {
val typeSize = ULong.SIZE_BYTES / Byte.SIZE_BYTES
assert(typeSize == this.size) { "ULong must have $typeSize bytes" }
return ByteBuffer.allocate(this.size).let {
it.order(inByteOrder)
it.put(this)
it.flip()
it.getLong().toULong()
}
}
//similar to this.toString(StandardCharsets.UTF_8).replace("${Character.MIN_VALUE}", "")
// not Deprecated for now, "1.3.41 experimental api: ByteArray.decodeToString()") is a little different
fun ByteArray.toCString(): String {
return this.toString(StandardCharsets.UTF_8).let { str ->
str.indexOf(Character.MIN_VALUE).let { nullPos ->
if (nullPos >= 0) str.substring(0, nullPos) else str
}
}
}
}//end-of-Companion
}//end-of-ByteArrayExt
}

@ -1,511 +0,0 @@
// Copyright 2021 yuyezhong@gmail.com
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package cfig.io
import cfig.helper.Helper
import cfig.io.Struct3Retire
import com.fasterxml.jackson.databind.ObjectMapper
import org.junit.Assert
import org.junit.Test
import java.io.ByteArrayInputStream
@OptIn(kotlin.ExperimentalUnsignedTypes::class)
class Struct3RetireTest {
private fun getConvertedFormats(inStruct: Struct3Retire): ArrayList<Map<String, Int>> {
val f = inStruct.javaClass.getDeclaredField("formats")
f.isAccessible = true
val formatDumps = arrayListOf<Map<String, Int>>()
(f.get(inStruct) as ArrayList<*>).apply {
this.forEach {
@Suppress("UNCHECKED_CAST")
val format = it as Array<Any>
val k = if (format[0].toString().indexOf(" ") > 0) {
format[0].toString().split(" ")[1]
} else {
format[0].toString()
}
formatDumps.add(mapOf(k to (format[1] as Int)))
}
}
return formatDumps
}
private fun constructorTestFun1(inFormatString: String) {
println(ObjectMapper().writeValueAsString(getConvertedFormats(Struct3Retire(inFormatString))))
}
@Test
fun constructorTest() {
constructorTestFun1("3s")
constructorTestFun1("5b")
constructorTestFun1("5x")
constructorTestFun1("2c")
}
@Test
fun calcSizeTest() {
Assert.assertEquals(3, Struct3Retire("3s").calcSize())
Assert.assertEquals(5, Struct3Retire("5b").calcSize())
Assert.assertEquals(5, Struct3Retire("5x").calcSize())
Assert.assertEquals(9, Struct3Retire("9c").calcSize())
}
@Test
fun toStringTest() {
println(Struct3Retire("!4s2L2QL11QL4x47sx80x"))
}
//x
@Test
fun paddingTest() {
Assert.assertEquals("0000000000", Helper.toHexString(Struct3Retire("5x").pack(null)))
Assert.assertEquals("0000000000", Helper.toHexString(Struct3Retire("5x").pack(0)))
Assert.assertEquals("0101010101", Helper.toHexString(Struct3Retire("5x").pack(1)))
Assert.assertEquals("1212121212", Helper.toHexString(Struct3Retire("5x").pack(0x12)))
//Integer高位被截掉
Assert.assertEquals("2323232323", Helper.toHexString(Struct3Retire("5x").pack(0x123)))
// minus 0001_0011 -> 补码 1110 1101ie. 0xed
Assert.assertEquals("ededededed", Helper.toHexString(Struct3Retire("5x").pack(-0x13)))
//0xff
Assert.assertEquals("ffffffffff", Helper.toHexString(Struct3Retire("5x").pack(-1)))
try {
Struct3Retire("5x").pack("bad")
Assert.assertTrue("should throw exception here", false)
} catch (e: IllegalArgumentException) {
}
//unpack
Struct3Retire("3x").unpack(ByteArrayInputStream(Helper.fromHexString("000000"))).let {
Assert.assertEquals(1, it.size)
Assert.assertEquals(0.toByte(), it[0])
}
Struct3Retire("x2xx").unpack(ByteArrayInputStream(Helper.fromHexString("01121210"))).let {
Assert.assertEquals(3, it.size)
Assert.assertEquals(0x1.toByte(), it[0])
Assert.assertEquals(0x12.toByte(), it[1])
Assert.assertEquals(0x10.toByte(), it[2])
}
}
//c
@Test
fun characterTest() {
//constructor
Struct3Retire("c")
//calcSize
Assert.assertEquals(3, Struct3Retire("3c").calcSize())
//pack illegal
try {
Struct3Retire("c").pack("a")
Assert.fail("should throw exception here")
} catch (e: Throwable) {
Assert.assertTrue(e is AssertionError || e is IllegalArgumentException)
}
//pack legal
Assert.assertEquals(
"61",
Helper.toHexString(Struct3Retire("!c").pack('a'))
)
Assert.assertEquals(
"61",
Helper.toHexString(Struct3Retire("c").pack('a'))
)
Assert.assertEquals(
"616263",
Helper.toHexString(Struct3Retire("3c").pack('a', 'b', 'c'))
)
//unpack
Struct3Retire("3c").unpack(ByteArrayInputStream(Helper.fromHexString("616263"))).let {
Assert.assertEquals(3, it.size)
Assert.assertEquals('a', it[0])
Assert.assertEquals('b', it[1])
Assert.assertEquals('c', it[2])
}
}
//b
@Test
fun bytesTest() {
//constructor
Struct3Retire("b")
//calcSize
Assert.assertEquals(3, Struct3Retire("3b").calcSize())
//pack
Assert.assertEquals(
"123456", Helper.toHexString(
Struct3Retire("3b").pack(byteArrayOf(0x12, 0x34, 0x56))
)
)
Assert.assertEquals(
"123456", Helper.toHexString(
Struct3Retire("!3b").pack(byteArrayOf(0x12, 0x34, 0x56))
)
)
Assert.assertEquals(
"123400", Helper.toHexString(
Struct3Retire("3b").pack(byteArrayOf(0x12, 0x34))
)
)
//unpack
Struct3Retire("3b").unpack(ByteArrayInputStream(Helper.fromHexString("123400"))).let {
Assert.assertEquals(1, it.size)
Assert.assertEquals("123400", Helper.toHexString(it[0] as ByteArray))
}
Struct3Retire("bbb").unpack(ByteArrayInputStream(Helper.fromHexString("123400"))).let {
Assert.assertEquals(3, it.size)
Assert.assertEquals("12", Helper.toHexString(it[0] as ByteArray))
Assert.assertEquals("34", Helper.toHexString(it[1] as ByteArray))
Assert.assertEquals("00", Helper.toHexString(it[2] as ByteArray))
}
}
//B: UByte array
@Test
fun uBytesTest() {
//constructor
Struct3Retire("B")
//calcSize
Assert.assertEquals(3, Struct3Retire("3B").calcSize())
//pack
Assert.assertEquals(
"123456", Helper.toHexString(
Struct3Retire("3B").pack(byteArrayOf(0x12, 0x34, 0x56))
)
)
Assert.assertEquals(
"123456", Helper.toHexString(
Struct3Retire("!3B").pack(byteArrayOf(0x12, 0x34, 0x56))
)
)
Assert.assertEquals(
"123400", Helper.toHexString(
Struct3Retire("3B").pack(byteArrayOf(0x12, 0x34))
)
)
//unpack
Struct3Retire("3B").unpack(ByteArrayInputStream(Helper.fromHexString("123400"))).let {
Assert.assertEquals(1, it.size)
Assert.assertEquals("123400", Helper.toHexString(it[0] as UByteArray))
}
Struct3Retire("BBB").unpack(ByteArrayInputStream(Helper.fromHexString("123400"))).let {
Assert.assertEquals(3, it.size)
Assert.assertEquals("12", Helper.toHexString(it[0] as UByteArray))
Assert.assertEquals("34", Helper.toHexString(it[1] as UByteArray))
Assert.assertEquals("00", Helper.toHexString(it[2] as UByteArray))
}
}
//s
@Test
fun stringTest() {
//constructor
Struct3Retire("s")
//calcSize
Assert.assertEquals(3, Struct3Retire("3s").calcSize())
//pack
Struct3Retire("3s").pack("a")
Struct3Retire("3s").pack("abc")
try {
Struct3Retire("3s").pack("abcd")
Assert.fail("should throw exception here")
} catch (e: Throwable) {
Assert.assertTrue(e.toString(), e is AssertionError || e is IllegalArgumentException)
}
//unpack
Struct3Retire("3s").unpack(ByteArrayInputStream(Helper.fromHexString("616263"))).let {
Assert.assertEquals(1, it.size)
Assert.assertEquals("abc", it[0])
}
Struct3Retire("3s").unpack(ByteArrayInputStream(Helper.fromHexString("610000"))).let {
Assert.assertEquals(1, it.size)
Assert.assertEquals("a", it[0])
}
}
//h
@Test
fun shortTest() {
//constructor
Struct3Retire("h")
//calcSize
Assert.assertEquals(6, Struct3Retire("3h").calcSize())
//pack
Assert.assertEquals("ff7f", Helper.toHexString(Struct3Retire("h").pack(0x7fff)))
Assert.assertEquals("0080", Helper.toHexString(Struct3Retire("h").pack(-0x8000)))
Assert.assertEquals("7fff0000", Helper.toHexString(Struct3Retire(">2h").pack(0x7fff, 0)))
//unpack
Struct3Retire(">2h").unpack(ByteArrayInputStream(Helper.fromHexString("7fff0000"))).let {
Assert.assertEquals(2, it.size)
Assert.assertEquals(0x7fff.toShort(), it[0])
Assert.assertEquals(0.toShort(), it[1])
}
}
//H
@Test
fun uShortTest() {
//constructor
Struct3Retire("H")
//calcSize
Assert.assertEquals(6, Struct3Retire("3H").calcSize())
//pack
Assert.assertEquals("0100", Helper.toHexString(Struct3Retire("H").pack((1U).toUShort())))
Assert.assertEquals("0100", Helper.toHexString(Struct3Retire("H").pack(1U)))
Assert.assertEquals("ffff", Helper.toHexString(Struct3Retire("H").pack(65535U)))
Assert.assertEquals("ffff", Helper.toHexString(Struct3Retire("H").pack(65535)))
try {
Struct3Retire("H").pack(-1)
Assert.fail("should throw exception here")
} catch (e: Throwable) {
Assert.assertTrue(e is AssertionError || e is IllegalArgumentException)
}
//unpack
Struct3Retire("H").unpack(ByteArrayInputStream(Helper.fromHexString("ffff"))).let {
Assert.assertEquals(1, it.size)
Assert.assertEquals(65535U.toUShort(), it[0])
}
}
//i, l
@Test
fun intTest() {
//constructor
Struct3Retire("i")
Struct3Retire("l")
//calcSize
Assert.assertEquals(12, Struct3Retire("3i").calcSize())
Assert.assertEquals(12, Struct3Retire("3l").calcSize())
//pack
Struct3Retire("i").pack(65535 + 1)
Struct3Retire("i").pack(-1)
//unpack
Struct3Retire("i").unpack(ByteArrayInputStream(Helper.fromHexString("00000100"))).let {
Assert.assertEquals(1, it.size)
Assert.assertEquals(65536, it[0])
}
Struct3Retire("i").unpack(ByteArrayInputStream(Helper.fromHexString("ffffffff"))).let {
Assert.assertEquals(1, it.size)
Assert.assertEquals(-1, it[0])
}
}
//I, L
@Test
fun uIntTest() {
//constructor
Struct3Retire("I")
Struct3Retire("L")
//calcSize
Assert.assertEquals(12, Struct3Retire("3I").calcSize())
Assert.assertEquals(12, Struct3Retire("3L").calcSize())
//pack
Assert.assertEquals(
"01000000", Helper.toHexString(
Struct3Retire("I").pack(1U)
)
)
Assert.assertEquals(
"80000000", Helper.toHexString(
Struct3Retire(">I").pack(Int.MAX_VALUE.toUInt() + 1U)
)
)
//unpack
Struct3Retire("I").unpack(ByteArrayInputStream(Helper.fromHexString("01000000"))).let {
Assert.assertEquals(1, it.size)
Assert.assertEquals(1U, it[0])
}
Struct3Retire(">I").unpack(ByteArrayInputStream(Helper.fromHexString("80000000"))).let {
Assert.assertEquals(1, it.size)
Assert.assertEquals(Int.MAX_VALUE.toUInt() + 1U, it[0])
}
}
//q: Long
@Test
fun longTest() {
//constructor
Struct3Retire("q")
//calcSize
Assert.assertEquals(24, Struct3Retire("3q").calcSize())
//pack
Assert.assertEquals(
"8000000000000000", Helper.toHexString(
Struct3Retire(">q").pack(Long.MIN_VALUE)
)
)
Assert.assertEquals(
"7fffffffffffffff", Helper.toHexString(
Struct3Retire(">q").pack(Long.MAX_VALUE)
)
)
Assert.assertEquals(
"ffffffffffffffff", Helper.toHexString(
Struct3Retire(">q").pack(-1L)
)
)
//unpack
Struct3Retire(">q").unpack(ByteArrayInputStream(Helper.fromHexString("8000000000000000"))).let {
Assert.assertEquals(1, it.size)
Assert.assertEquals(Long.MIN_VALUE, it[0])
}
Struct3Retire(">q").unpack(ByteArrayInputStream(Helper.fromHexString("7fffffffffffffff"))).let {
Assert.assertEquals(1, it.size)
Assert.assertEquals(Long.MAX_VALUE, it[0])
}
Struct3Retire(">q").unpack(ByteArrayInputStream(Helper.fromHexString("ffffffffffffffff"))).let {
Assert.assertEquals(1, it.size)
Assert.assertEquals(-1L, it[0])
}
}
//Q: ULong
@Test
fun uLongTest() {
//constructor
Struct3Retire("Q")
//calcSize
Assert.assertEquals(24, Struct3Retire("3Q").calcSize())
//pack
Assert.assertEquals(
"7fffffffffffffff", Helper.toHexString(
Struct3Retire(">Q").pack(Long.MAX_VALUE)
)
)
Assert.assertEquals(
"0000000000000000", Helper.toHexString(
Struct3Retire(">Q").pack(ULong.MIN_VALUE)
)
)
Assert.assertEquals(
"ffffffffffffffff", Helper.toHexString(
Struct3Retire(">Q").pack(ULong.MAX_VALUE)
)
)
try {
Struct3Retire(">Q").pack(-1L)
} catch (e: Throwable) {
Assert.assertTrue(e is AssertionError || e is IllegalArgumentException)
}
//unpack
Struct3Retire(">Q").unpack(ByteArrayInputStream(Helper.fromHexString("7fffffffffffffff"))).let {
Assert.assertEquals(1, it.size)
Assert.assertEquals(Long.MAX_VALUE.toULong(), it[0])
}
Struct3Retire(">Q").unpack(ByteArrayInputStream(Helper.fromHexString("0000000000000000"))).let {
Assert.assertEquals(1, it.size)
Assert.assertEquals(ULong.MIN_VALUE, it[0])
}
Struct3Retire(">Q").unpack(ByteArrayInputStream(Helper.fromHexString("ffffffffffffffff"))).let {
Assert.assertEquals(1, it.size)
Assert.assertEquals(ULong.MAX_VALUE, it[0])
}
}
@Test
fun legacyTest() {
Assert.assertTrue(
Struct3Retire("<2i4b4b").pack(
1, 7321, byteArrayOf(1, 2, 3, 4), byteArrayOf(200.toByte(), 201.toByte(), 202.toByte(), 203.toByte())
)
.contentEquals(Helper.fromHexString("01000000991c000001020304c8c9cacb"))
)
Assert.assertTrue(
Struct3Retire("<2i4b4B").pack(
1, 7321, byteArrayOf(1, 2, 3, 4), intArrayOf(200, 201, 202, 203)
)
.contentEquals(Helper.fromHexString("01000000991c000001020304c8c9cacb"))
)
Assert.assertTrue(Struct3Retire("b2x").pack(byteArrayOf(0x13), null).contentEquals(Helper.fromHexString("130000")))
Assert.assertTrue(
Struct3Retire("b2xi").pack(byteArrayOf(0x13), null, 55).contentEquals(Helper.fromHexString("13000037000000"))
)
Struct3Retire("5s").pack("Good").contentEquals(Helper.fromHexString("476f6f6400"))
Struct3Retire("5s1b").pack("Good", byteArrayOf(13)).contentEquals(Helper.fromHexString("476f6f64000d"))
}
@Test
fun legacyIntegerLE() {
//int (4B)
Assert.assertTrue(Struct3Retire("<2i").pack(1, 7321).contentEquals(Helper.fromHexString("01000000991c0000")))
val ret = Struct3Retire("<2i").unpack(ByteArrayInputStream(Helper.fromHexString("01000000991c0000")))
Assert.assertEquals(2, ret.size)
Assert.assertTrue(ret[0] is Int)
Assert.assertTrue(ret[1] is Int)
Assert.assertEquals(1, ret[0] as Int)
Assert.assertEquals(7321, ret[1] as Int)
//unsigned int (4B)
Assert.assertTrue(Struct3Retire("<I").pack(2L).contentEquals(Helper.fromHexString("02000000")))
Assert.assertTrue(Struct3Retire("<I").pack(2).contentEquals(Helper.fromHexString("02000000")))
//greater than Int.MAX_VALUE
Assert.assertTrue(Struct3Retire("<I").pack(2147483748L).contentEquals(Helper.fromHexString("64000080")))
Assert.assertTrue(Struct3Retire("<I").pack(2147483748).contentEquals(Helper.fromHexString("64000080")))
try {
Struct3Retire("<I").pack(-12)
throw Exception("should not reach here")
} catch (e: Throwable) {
Assert.assertTrue(e is AssertionError || e is IllegalArgumentException)
}
//negative int
Assert.assertTrue(Struct3Retire("<i").pack(-333).contentEquals(Helper.fromHexString("b3feffff")))
}
@Test
fun legacyIntegerBE() {
run {
Assert.assertTrue(Struct3Retire(">2i").pack(1, 7321).contentEquals(Helper.fromHexString("0000000100001c99")))
val ret = Struct3Retire(">2i").unpack(ByteArrayInputStream(Helper.fromHexString("0000000100001c99")))
Assert.assertEquals(1, ret[0] as Int)
Assert.assertEquals(7321, ret[1] as Int)
}
run {
Assert.assertTrue(Struct3Retire("!i").pack(-333).contentEquals(Helper.fromHexString("fffffeb3")))
val ret2 = Struct3Retire("!i").unpack(ByteArrayInputStream(Helper.fromHexString("fffffeb3")))
Assert.assertEquals(-333, ret2[0] as Int)
}
}
}

@ -1,4 +1,4 @@
package cfig.io
package cc.cfig.io
import cfig.helper.Helper
import org.junit.Assert

Loading…
Cancel
Save