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 package avb.alg
import cfig.io.Struct3 import cc.cfig.io.Struct3
class Algorithms { class Algorithms {
companion object { companion object {

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists 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 zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists

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

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

@ -14,9 +14,9 @@
package cfig.helper package cfig.helper
import cc.cfig.io.Struct3
import cfig.helper.Helper.Companion.check_call import cfig.helper.Helper.Companion.check_call
import cfig.helper.Helper.Companion.check_output 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.ZipArchiveEntry
import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream
import org.apache.commons.compress.archivers.zip.ZipArchiveInputStream 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.IOException
import java.io.InputStream import java.io.InputStream
import java.nio.ByteBuffer import java.nio.ByteBuffer
@ -72,7 +84,7 @@ class Struct3(inFormatString: String) {
return ByteBuffer.allocate(this.calcSize()).let { bf -> return ByteBuffer.allocate(this.calcSize()).let { bf ->
bf.order(this.byteOrder) bf.order(this.byteOrder)
args.forEachIndexed { index, arg -> args.forEachIndexed { index, arg ->
warships.get(index).put(bf, arg) warships[index].put(bf, arg)
} }
bf.array() bf.array()
} }
@ -86,7 +98,6 @@ class Struct3(inFormatString: String) {
private interface IWarShip<T> { private interface IWarShip<T> {
val sz: Int val sz: Int
var multiple: Int var multiple: Int
val log: Logger
fun get(stream: InputStream, byteOrder: ByteOrder): T fun get(stream: InputStream, byteOrder: ByteOrder): T
fun get(ba: ByteArray, byteOrder: ByteOrder): T fun get(ba: ByteArray, byteOrder: ByteOrder): T
fun put(bf: ByteBuffer, arg: Any?) fun put(bf: ByteBuffer, arg: Any?)
@ -112,7 +123,7 @@ class Struct3(inFormatString: String) {
it.order(byteOrder) it.order(byteOrder)
it.put(ba) it.put(ba)
it.flip() it.flip()
it.getShort() it.short
} }
} }
@ -133,7 +144,6 @@ class Struct3(inFormatString: String) {
} }
override val sz: Int = Short.SIZE_BYTES override val sz: Int = Short.SIZE_BYTES
override val log: Logger = LoggerFactory.getLogger(ShortShip::class.java)
} }
private class UShortShip : IBaseShip<UShort> { private class UShortShip : IBaseShip<UShort> {
@ -150,7 +160,7 @@ class Struct3(inFormatString: String) {
it.order(byteOrder) it.order(byteOrder)
it.put(ba) it.put(ba)
it.flip() 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 sz: Int = UShort.SIZE_BYTES
override val log: Logger = LoggerFactory.getLogger(UShortShip::class.java)
} }
//i, l: Int //i, l: Int
@ -193,7 +202,7 @@ class Struct3(inFormatString: String) {
it.order(byteOrder) it.order(byteOrder)
it.put(ba) it.put(ba)
it.flip() it.flip()
it.getInt() it.int
} }
} }
@ -207,7 +216,6 @@ class Struct3(inFormatString: String) {
} }
override val sz: Int = Int.SIZE_BYTES override val sz: Int = Int.SIZE_BYTES
override val log: Logger = LoggerFactory.getLogger(IntShip::class.java)
} }
//I, L: UInt //I, L: UInt
@ -225,7 +233,7 @@ class Struct3(inFormatString: String) {
it.order(byteOrder) it.order(byteOrder)
it.put(ba) it.put(ba)
it.flip() 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 sz: Int = UInt.SIZE_BYTES
override val log: Logger = LoggerFactory.getLogger(UIntShip::class.java)
} }
//q: Long //q: Long
@ -267,7 +274,7 @@ class Struct3(inFormatString: String) {
it.order(byteOrder) it.order(byteOrder)
it.put(ba) it.put(ba)
it.flip() it.flip()
it.getLong() it.long
} }
} }
@ -284,7 +291,6 @@ class Struct3(inFormatString: String) {
} }
override val sz: Int = Long.SIZE_BYTES override val sz: Int = Long.SIZE_BYTES
override val log: Logger = LoggerFactory.getLogger(LongShip::class.java)
} }
//Q: ULong //Q: ULong
@ -302,7 +308,7 @@ class Struct3(inFormatString: String) {
it.order(byteOrder) it.order(byteOrder)
it.put(ba) it.put(ba)
it.flip() 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 sz: Int = ULong.SIZE_BYTES
override val log: Logger = LoggerFactory.getLogger(ULongShip::class.java)
} }
//c: character //c: character
@ -338,7 +343,7 @@ class Struct3(inFormatString: String) {
} }
override fun get(ba: ByteArray, byteOrder: ByteOrder): Char { 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?) { override fun put(bf: ByteBuffer, arg: Any?) {
@ -354,21 +359,20 @@ class Struct3(inFormatString: String) {
} }
override val sz: Int = 1 override val sz: Int = 1
override val log: Logger = LoggerFactory.getLogger(CharShip::class.java)
} }
private interface IBaseFleet<T> : IWarShip<T> { private interface IBaseFleet<T> : IWarShip<T> {
fun appendPadding(bf: ByteBuffer, b: Byte, bufSize: Int) { fun appendPadding(bf: ByteBuffer, b: Byte, bufSize: Int) {
when { when {
bufSize == 0 -> { bufSize == 0 -> {
log.debug("paddingSize is zero, perfect match") //"paddingSize is zero, perfect match"
return return
} }
bufSize < 0 -> { bufSize < 0 -> {
throw IllegalArgumentException("illegal padding size: $bufSize") throw IllegalArgumentException("illegal padding size: $bufSize")
} }
else -> { else -> {
log.debug("paddingSize $bufSize") //"paddingSize $bufSize"
} }
} }
val padding = ByteArray(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") if (paddingSize < 0) throw IllegalArgumentException("arg length [${inByteArray.size}] exceeds limit: $bufSize")
//data //data
bf.put(inByteArray) bf.put(inByteArray)
//padding //padding: "paddingSize $paddingSize"
appendPadding(bf, 0.toByte(), paddingSize) appendPadding(bf, 0.toByte(), paddingSize)
log.debug("paddingSize $paddingSize")
} }
fun appendByteArray(bf: ByteBuffer, inIntArray: IntArray, bufSize: Int) { fun appendByteArray(bf: ByteBuffer, inIntArray: IntArray, bufSize: Int) {
@ -429,7 +432,7 @@ class Struct3(inFormatString: String) {
} }
override fun get(ba: ByteArray, byteOrder: ByteOrder): Byte { override fun get(ba: ByteArray, byteOrder: ByteOrder): Byte {
TODO("Not yet implemented") return ba[0]
} }
override fun put(bf: ByteBuffer, arg: Any?) { override fun put(bf: ByteBuffer, arg: Any?) {
@ -444,8 +447,6 @@ class Struct3(inFormatString: String) {
override fun toString(): String { override fun toString(): String {
return "${multiple}x" return "${multiple}x"
} }
override val log: Logger = LoggerFactory.getLogger(PaddingFleet::class.java)
} }
//b: byte array //b: byte array
@ -457,7 +458,8 @@ class Struct3(inFormatString: String) {
} }
override fun get(ba: ByteArray, byteOrder: ByteOrder): ByteArray { 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?) { override fun put(bf: ByteBuffer, arg: Any?) {
@ -473,7 +475,6 @@ class Struct3(inFormatString: String) {
} }
override val sz: Int = Byte.SIZE_BYTES override val sz: Int = Byte.SIZE_BYTES
override val log: Logger = LoggerFactory.getLogger(ByteFleet::class.java)
} }
//B: UByte array //B: UByte array
@ -486,6 +487,10 @@ class Struct3(inFormatString: String) {
return innerData2.toUByteArray() return innerData2.toUByteArray()
} }
override fun get(ba: ByteArray, byteOrder: ByteOrder): UByteArray {
return ba.toUByteArray()
}
override fun put(bf: ByteBuffer, arg: Any?) { override fun put(bf: ByteBuffer, arg: Any?) {
when (arg) { when (arg) {
is ByteArray -> appendByteArray(bf, arg, multiple) is ByteArray -> appendByteArray(bf, arg, multiple)
@ -501,12 +506,6 @@ class Struct3(inFormatString: String) {
override val sz: Int override val sz: Int
get() = UByte.SIZE_BYTES 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 //s: String
@ -536,6 +535,5 @@ class Struct3(inFormatString: String) {
} }
override val sz: Int = 1 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 cfig.helper.Helper
import org.junit.Assert import org.junit.Assert

Loading…
Cancel
Save