diff --git a/.gitignore b/.gitignore
index 38074aa..bfb6357 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,5 +1,4 @@
 .idea
 .gradle
 build/
-boot.img*
-local.properties
\ No newline at end of file
+local.properties
diff --git a/README.md b/README.md
index 368539b..1b6f1b1 100644
--- a/README.md
+++ b/README.md
@@ -10,7 +10,7 @@ A tool for reverse engineering Android ROM images.
 
 Mac: `brew install lz4 xz dtc`
 
-Linux: `sudo apt install git device-tree-compiler lz4 xz-utils zlib1g-dev openjdk-11-jdk gcc g++ python3`
+Linux: `sudo apt install git device-tree-compiler lz4 xz-utils zlib1g-dev openjdk-11-jdk gcc g++ python3 python-is-python3`
 
 Windows Subsystem for Linux(WSL): `sudo apt install git device-tree-compiler lz4 xz-utils zlib1g-dev openjdk-11-jdk gcc g++ python`
 
diff --git a/bbootimg/build.gradle.kts b/bbootimg/build.gradle.kts
index c6533cd..e47b369 100644
--- a/bbootimg/build.gradle.kts
+++ b/bbootimg/build.gradle.kts
@@ -15,7 +15,7 @@
 import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
 
 plugins {
-    kotlin("jvm") version "1.5.30"
+    kotlin("jvm") version "1.5.31"
     application
 }
 
@@ -56,7 +56,10 @@ application {
 }
 
 tasks.withType<KotlinCompile>().all {
-    kotlinOptions.freeCompilerArgs += "-Xopt-in=kotlin.RequiresOptIn"
+    kotlinOptions {
+        freeCompilerArgs += "-Xopt-in=kotlin.RequiresOptIn"
+        jvmTarget = "11"
+    }
 }
 
 tasks {
diff --git a/bbootimg/src/main/kotlin/avb/AVBInfo.kt b/bbootimg/src/main/kotlin/avb/AVBInfo.kt
index 322ef87..cb61182 100644
--- a/bbootimg/src/main/kotlin/avb/AVBInfo.kt
+++ b/bbootimg/src/main/kotlin/avb/AVBInfo.kt
@@ -88,121 +88,93 @@ class AVBInfo(
         private val log = LoggerFactory.getLogger(AVBInfo::class.java)
         private val mapper = ObjectMapper()
 
-        fun parseFrom(imageFile: String): AVBInfo {
-            log.info("parseFrom($imageFile) ...")
-            var footer: Footer? = null
-            var vbMetaOffset: Long = 0
+        private data class Glance(
+            var footer: Footer?,
+            var vbMetaOffset: Long
+        )
+
+        private fun imageGlance(imageFile: String): Glance {
+            val ret = Glance(null, 0)
             // footer
             FileInputStream(imageFile).use { fis ->
                 fis.skip(File(imageFile).length() - Footer.SIZE)
                 try {
-                    footer = Footer(fis)
-                    vbMetaOffset = footer!!.vbMetaOffset
-                    log.info("$imageFile: $footer")
+                    ret.footer = Footer(fis)
+                    ret.vbMetaOffset = ret.footer!!.vbMetaOffset
+                    log.info("$imageFile: $ret.footer")
                 } catch (e: IllegalArgumentException) {
                     log.info("image $imageFile has no AVB Footer")
                 }
             }
+            return ret
+        }
+
+        fun parseFrom(imageFile: String): AVBInfo {
+            log.info("parseFrom($imageFile) ...")
+            // glance
+            val (footer, vbMetaOffset) = imageGlance(imageFile)
             // header
-            val rawHeaderBlob = ByteArray(Header.SIZE).apply {
-                FileInputStream(imageFile).use { fis ->
-                    fis.skip(vbMetaOffset)
-                    fis.read(this)
-                }
-            }
-            val vbMetaHeader = Header(ByteArrayInputStream(rawHeaderBlob))
-            log.debug(vbMetaHeader.toString())
+            val vbMetaHeader = Header(ByteArrayInputStream(Helper.readFully(imageFile, vbMetaOffset, Header.SIZE)))
             log.debug(mapper.writerWithDefaultPrettyPrinter().writeValueAsString(vbMetaHeader))
 
-            val authBlockOffset = vbMetaOffset + Header.SIZE
-            val auxBlockOffset = authBlockOffset + vbMetaHeader.authentication_data_block_size
+            val atlas = mutableMapOf<String, Pair<Long, Int>>()
+            atlas["auth"] =
+                Pair(vbMetaOffset + Header.SIZE, vbMetaHeader.authentication_data_block_size.toInt())
+            atlas["auth.hash"] =
+                Pair(atlas["auth"]!!.first + vbMetaHeader.hash_offset, vbMetaHeader.hash_size.toInt())
+            atlas["auth.sig"] =
+                Pair(atlas["auth.hash"]!!.first + atlas["auth.hash"]!!.second, vbMetaHeader.signature_size.toInt())
+            atlas["aux"] =
+                Pair(atlas["auth"]!!.first + atlas["auth"]!!.second, vbMetaHeader.auxiliary_data_block_size.toInt())
 
             val ai = AVBInfo(vbMetaHeader, null, AuxBlob(), footer)
             // Auth blob
             if (vbMetaHeader.authentication_data_block_size > 0) {
-                FileInputStream(imageFile).use { fis ->
-                    fis.skip(vbMetaOffset)
-                    fis.skip(Header.SIZE.toLong())
-                    fis.skip(vbMetaHeader.hash_offset)
-                    val ba = ByteArray(vbMetaHeader.hash_size.toInt())
-                    fis.read(ba)
-                    log.debug("Parsed Auth Hash (Header & Aux Blob): " + Hex.encodeHexString(ba))
-                    val bb = ByteArray(vbMetaHeader.signature_size.toInt())
-                    fis.read(bb)
-                    log.debug("Parsed Auth Signature (of hash): " + Hex.encodeHexString(bb))
-                    ai.authBlob = AuthBlob()
-                    ai.authBlob!!.offset = authBlockOffset
-                    ai.authBlob!!.size = vbMetaHeader.authentication_data_block_size
-                    ai.authBlob!!.hash = Hex.encodeHexString(ba)
-                    ai.authBlob!!.signature = Hex.encodeHexString(bb)
-                }
+                val ba = Helper.readFully(imageFile, atlas["auth.hash"]!!)
+                log.debug("Parsed Auth Hash (Header & Aux Blob): " + Hex.encodeHexString(ba))
+                val bb = Helper.readFully(imageFile, atlas["auth.sig"]!!)
+                log.debug("Parsed Auth Signature (of hash): " + Hex.encodeHexString(bb))
+                ai.authBlob = AuthBlob()
+                ai.authBlob!!.offset = atlas["auth"]!!.first
+                ai.authBlob!!.size = atlas["auth"]!!.second.toLong()
+                ai.authBlob!!.hash = Hex.encodeHexString(ba)
+                ai.authBlob!!.signature = Hex.encodeHexString(bb)
             }
             // aux
-            val rawAuxBlob = ByteArray(vbMetaHeader.auxiliary_data_block_size.toInt()).apply {
-                FileInputStream(imageFile).use { fis ->
-                    fis.skip(auxBlockOffset)
-                    fis.read(this)
-                }
-            }
+            val rawAuxBlob = Helper.readFully(imageFile, atlas["aux"]!!)
             // aux - desc
-            var descriptors: List<Any>
             if (vbMetaHeader.descriptors_size > 0) {
-                ByteArrayInputStream(rawAuxBlob).use { bis ->
-                    bis.skip(vbMetaHeader.descriptors_offset)
-                    descriptors = UnknownDescriptor.parseDescriptors2(bis, vbMetaHeader.descriptors_size)
-                }
-                descriptors.forEach {
-                    log.debug(it.toString())
-                    when (it) {
-                        is PropertyDescriptor -> {
-                            ai.auxBlob!!.propertyDescriptors.add(it)
-                        }
-                        is HashDescriptor -> {
-                            ai.auxBlob!!.hashDescriptors.add(it)
-                        }
-                        is KernelCmdlineDescriptor -> {
-                            ai.auxBlob!!.kernelCmdlineDescriptors.add(it)
-                        }
-                        is HashTreeDescriptor -> {
-                            ai.auxBlob!!.hashTreeDescriptors.add(it)
-                        }
-                        is ChainPartitionDescriptor -> {
-                            ai.auxBlob!!.chainPartitionDescriptors.add(it)
-                        }
-                        is UnknownDescriptor -> {
-                            ai.auxBlob!!.unknownDescriptors.add(it)
-                        }
-                        else -> {
-                            throw IllegalArgumentException("invalid descriptor: $it")
-                        }
-                    }
-                }
+                val descriptors = UnknownDescriptor.parseDescriptors2(
+                    ByteArrayInputStream(
+                        rawAuxBlob.copyOfRange(vbMetaHeader.descriptors_offset.toInt(), rawAuxBlob.size)
+                    ),
+                    vbMetaHeader.descriptors_size
+                )
+                ai.auxBlob!!.populateDescriptors(descriptors)
+            } else {
+                log.warn("no descriptors in AVB aux blob")
             }
             // aux - pubkey
             if (vbMetaHeader.public_key_size > 0) {
                 ai.auxBlob!!.pubkey = AuxBlob.PubKeyInfo()
                 ai.auxBlob!!.pubkey!!.offset = vbMetaHeader.public_key_offset
                 ai.auxBlob!!.pubkey!!.size = vbMetaHeader.public_key_size
-
-                ByteArrayInputStream(rawAuxBlob).use { bis ->
-                    bis.skip(vbMetaHeader.public_key_offset)
-                    ai.auxBlob!!.pubkey!!.pubkey = ByteArray(vbMetaHeader.public_key_size.toInt())
-                    bis.read(ai.auxBlob!!.pubkey!!.pubkey)
-                    log.debug("Parsed Pub Key: " + Hex.encodeHexString(ai.auxBlob!!.pubkey!!.pubkey))
-                }
+                ai.auxBlob!!.pubkey!!.pubkey = rawAuxBlob.copyOfRange(
+                    vbMetaHeader.public_key_offset.toInt(),
+                    (vbMetaHeader.public_key_offset + vbMetaHeader.public_key_size).toInt()
+                )
+                log.debug("Parsed Pub Key: " + Hex.encodeHexString(ai.auxBlob!!.pubkey!!.pubkey))
             }
             // aux - pkmd
             if (vbMetaHeader.public_key_metadata_size > 0) {
                 ai.auxBlob!!.pubkeyMeta = AuxBlob.PubKeyMetadataInfo()
                 ai.auxBlob!!.pubkeyMeta!!.offset = vbMetaHeader.public_key_metadata_offset
                 ai.auxBlob!!.pubkeyMeta!!.size = vbMetaHeader.public_key_metadata_size
-
-                ByteArrayInputStream(rawAuxBlob).use { bis ->
-                    bis.skip(vbMetaHeader.public_key_metadata_offset)
-                    ai.auxBlob!!.pubkeyMeta!!.pkmd = ByteArray(vbMetaHeader.public_key_metadata_size.toInt())
-                    bis.read(ai.auxBlob!!.pubkeyMeta!!.pkmd)
-                    log.debug("Parsed Pub Key Metadata: " + Helper.toHexString(ai.auxBlob!!.pubkeyMeta!!.pkmd))
-                }
+                ai.auxBlob!!.pubkeyMeta!!.pkmd = rawAuxBlob.copyOfRange(
+                    vbMetaHeader.public_key_metadata_offset.toInt(),
+                    (vbMetaHeader.public_key_metadata_offset + vbMetaHeader.public_key_metadata_size).toInt()
+                )
+                log.debug("Parsed Pub Key Metadata: " + Helper.toHexString(ai.auxBlob!!.pubkeyMeta!!.pkmd))
             }
             log.debug("vbmeta info of [$imageFile] has been analyzed")
             return ai
diff --git a/bbootimg/src/main/kotlin/avb/blob/AuxBlob.kt b/bbootimg/src/main/kotlin/avb/blob/AuxBlob.kt
index 4c442e4..e61d3e3 100644
--- a/bbootimg/src/main/kotlin/avb/blob/AuxBlob.kt
+++ b/bbootimg/src/main/kotlin/avb/blob/AuxBlob.kt
@@ -14,6 +14,7 @@
 
 package avb.blob
 
+import avb.AVBInfo
 import avb.alg.Algorithm
 import avb.desc.*
 import cfig.helper.Helper
@@ -101,6 +102,36 @@ class AuxBlob(
         return Struct3("${auxSize}b").pack(Helper.join(encodedDesc, encodedKey, encodedPkmd))
     }
 
+    fun populateDescriptors(descriptors: List<Descriptor>): AuxBlob {
+        descriptors.forEach {
+            log.debug(it.toString())
+            when (it) {
+                is PropertyDescriptor -> {
+                    this.propertyDescriptors.add(it)
+                }
+                is HashDescriptor -> {
+                    this.hashDescriptors.add(it)
+                }
+                is KernelCmdlineDescriptor -> {
+                    this.kernelCmdlineDescriptors.add(it)
+                }
+                is HashTreeDescriptor -> {
+                    this.hashTreeDescriptors.add(it)
+                }
+                is ChainPartitionDescriptor -> {
+                    this.chainPartitionDescriptors.add(it)
+                }
+                is UnknownDescriptor -> {
+                    this.unknownDescriptors.add(it)
+                }
+                else -> {
+                    throw IllegalArgumentException("invalid descriptor: $it")
+                }
+            }
+        }
+        return this
+    }
+
     companion object {
         fun encodePubKey(alg: Algorithm, key: ByteArray? = null): ByteArray {
             var encodedKey = byteArrayOf()
diff --git a/bbootimg/src/main/kotlin/avb/desc/ChainPartitionDescriptor.kt b/bbootimg/src/main/kotlin/avb/desc/ChainPartitionDescriptor.kt
index 1db033a..db398c2 100644
--- a/bbootimg/src/main/kotlin/avb/desc/ChainPartitionDescriptor.kt
+++ b/bbootimg/src/main/kotlin/avb/desc/ChainPartitionDescriptor.kt
@@ -58,7 +58,7 @@ class ChainPartitionDescriptor(
 
     constructor(data: InputStream, seq: Int = 0) : this() {
         if (SIZE - RESERVED != Struct3(FORMAT_STRING).calcSize().toLong()) {
-            throw RuntimeException()
+            throw RuntimeException("ChainPartitionDescriptor size check failed")
         }
         this.sequence = seq
         val info = Struct3(FORMAT_STRING + "${RESERVED}s").unpack(data)
diff --git a/bbootimg/src/main/kotlin/avb/desc/HashTreeDescriptor.kt b/bbootimg/src/main/kotlin/avb/desc/HashTreeDescriptor.kt
index 982fca6..2c10510 100644
--- a/bbootimg/src/main/kotlin/avb/desc/HashTreeDescriptor.kt
+++ b/bbootimg/src/main/kotlin/avb/desc/HashTreeDescriptor.kt
@@ -245,7 +245,7 @@ class HashTreeDescriptor(
             var hashOffset: Long = 0
         ) {
             override fun toString(): String {
-                return String.format(
+                return String.format(Locale.getDefault(),
                     "MT{data: %10s(%6s blocks), hash: %7s @%-5s}",
                     dataSize,
                     dataBlockCount,
diff --git a/bbootimg/src/main/kotlin/avb/desc/PropertyDescriptor.kt b/bbootimg/src/main/kotlin/avb/desc/PropertyDescriptor.kt
index 05c1d13..c9dfab0 100644
--- a/bbootimg/src/main/kotlin/avb/desc/PropertyDescriptor.kt
+++ b/bbootimg/src/main/kotlin/avb/desc/PropertyDescriptor.kt
@@ -23,7 +23,7 @@ class PropertyDescriptor(
         var value: String = "") : Descriptor(TAG, 0, 0) {
     override fun encode(): ByteArray {
         if (SIZE != Struct3(FORMAT_STRING).calcSize().toUInt()) {
-            throw RuntimeException()
+            throw RuntimeException("PropertyDesc size check failed")
         }
         this.num_bytes_following = (SIZE + this.key.length.toUInt() + this.value.length.toUInt() + 2U - 16U).toLong()
         val nbfWithPadding = Helper.round_to_multiple(this.num_bytes_following.toLong(), 8).toULong()
diff --git a/bbootimg/src/main/kotlin/bootloader_message/BootControl.kt b/bbootimg/src/main/kotlin/bcb/BootControl.kt
similarity index 97%
rename from bbootimg/src/main/kotlin/bootloader_message/BootControl.kt
rename to bbootimg/src/main/kotlin/bcb/BootControl.kt
index 6985fa4..5609eba 100644
--- a/bbootimg/src/main/kotlin/bootloader_message/BootControl.kt
+++ b/bbootimg/src/main/kotlin/bcb/BootControl.kt
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package cfig.bootloader_message
+package cfig.bcb
 
 class BootControl {
     data class SlotMetadata(//size: 16
diff --git a/bbootimg/src/main/kotlin/bootloader_message/BootloaderMsg.kt b/bbootimg/src/main/kotlin/bcb/BootloaderMsg.kt
similarity index 99%
rename from bbootimg/src/main/kotlin/bootloader_message/BootloaderMsg.kt
rename to bbootimg/src/main/kotlin/bcb/BootloaderMsg.kt
index c7ab1a2..6b9bf07 100644
--- a/bbootimg/src/main/kotlin/bootloader_message/BootloaderMsg.kt
+++ b/bbootimg/src/main/kotlin/bcb/BootloaderMsg.kt
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package cfig.bootloader_message
+package cfig.bcb
 
 import cfig.io.Struct3
 import org.slf4j.LoggerFactory
diff --git a/bbootimg/src/main/kotlin/bootloader_message/BootloaderMsgAB.kt b/bbootimg/src/main/kotlin/bcb/BootloaderMsgAB.kt
similarity index 98%
rename from bbootimg/src/main/kotlin/bootloader_message/BootloaderMsgAB.kt
rename to bbootimg/src/main/kotlin/bcb/BootloaderMsgAB.kt
index db01ae4..ad202cb 100644
--- a/bbootimg/src/main/kotlin/bootloader_message/BootloaderMsgAB.kt
+++ b/bbootimg/src/main/kotlin/bcb/BootloaderMsgAB.kt
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package cfig.bootloader_message
+package cfig.bcb
 
 import cfig.io.Struct3
 import org.slf4j.LoggerFactory
diff --git a/bbootimg/src/main/kotlin/bootloader_message/VirtualABMsg.kt b/bbootimg/src/main/kotlin/bcb/VirtualABMsg.kt
similarity index 53%
rename from bbootimg/src/main/kotlin/bootloader_message/VirtualABMsg.kt
rename to bbootimg/src/main/kotlin/bcb/VirtualABMsg.kt
index 538de35..43ef411 100644
--- a/bbootimg/src/main/kotlin/bootloader_message/VirtualABMsg.kt
+++ b/bbootimg/src/main/kotlin/bcb/VirtualABMsg.kt
@@ -12,23 +12,25 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package cfig.bootloader_message
+package cfig.bcb
 
+import cfig.helper.Helper
 import cfig.io.Struct3
 import org.slf4j.LoggerFactory
 import java.io.FileInputStream
 
 data class VirtualABMsg(
-        var version: Int = 0,
-        var magic: ByteArray = byteArrayOf(),
-        var mergeStatus: Int = 0,
-        var sourceSlot: Int = 0,
-        var reserved: ByteArray = byteArrayOf()
+    var version: Int = 0,
+    var magic: ByteArray = byteArrayOf(),
+    var mergeStatus: Int = 0,
+    var sourceSlot: Int = 0,
+    var reserved: ByteArray = byteArrayOf()
 ) {
     companion object {
         private const val FORMAT_STRING = "b4bbb57b"
         const val SIZE = 64
         private val log = LoggerFactory.getLogger("VirtualABMsg")
+        private const val MAGIC = "b00a7456"
 
         init {
             assert(SIZE == Struct3(FORMAT_STRING).calcSize())
@@ -37,19 +39,36 @@ data class VirtualABMsg(
 
     constructor(fis: FileInputStream) : this() {
         val info = Struct3(FORMAT_STRING).unpack(fis)
-        this.version = info[0] as Int
+        this.version = (info[0] as ByteArray)[0].toInt()
         this.magic = info[1] as ByteArray
-        this.mergeStatus = info[2] as Int
-        this.sourceSlot = info[3] as Int
+        this.mergeStatus = (info[2] as ByteArray)[0].toInt()
+        this.sourceSlot = (info[3] as ByteArray)[0].toInt()
         this.reserved = info[4] as ByteArray
+        if (MAGIC != Helper.Companion.toHexString(this.magic)) {
+            throw IllegalArgumentException("stream is not VirtualAB message")
+        }
     }
 
     fun encode(): ByteArray {
         return Struct3(FORMAT_STRING).pack(
-                this.version,
-                this.magic,
-                this.mergeStatus,
-                this.sourceSlot,
-                0)
+            this.version,
+            this.magic,
+            this.mergeStatus,
+            this.sourceSlot,
+            0
+        )
+    }
+
+    override fun toString(): String {
+        return "VABMsg(v=$version, magic=${Helper.toHexString(magic)}, mergeStatus=$mergeStatus:${MergeStatus.values().get(this.mergeStatus)}, sourceSlot=$sourceSlot)"
+    }
+
+
+    enum class MergeStatus(val status: Int) {
+        NONE(0),
+        UNKNOWN(1),
+        SNAPSHOTTED(2),
+        MERGING(3),
+        CANCELLED(4)
     }
 }
diff --git a/bbootimg/src/main/kotlin/bootimg/Common.kt b/bbootimg/src/main/kotlin/bootimg/Common.kt
index e5cafb7..c43bc3e 100644
--- a/bbootimg/src/main/kotlin/bootimg/Common.kt
+++ b/bbootimg/src/main/kotlin/bootimg/Common.kt
@@ -14,13 +14,13 @@
 
 package cfig.bootimg
 
-import cfig.EnvironmentVerifier
+import cfig.utils.EnvironmentVerifier
 import cfig.bootimg.cpio.AndroidCpio
-import cfig.dtb_util.DTC
+import cfig.utils.DTC
 import cfig.helper.Helper
 import cfig.helper.ZipHelper
 import cfig.io.Struct3.InputStreamExt.Companion.getInt
-import cfig.kernel_util.KernelExtractor
+import cfig.utils.KernelExtractor
 import org.apache.commons.exec.CommandLine
 import org.apache.commons.exec.DefaultExecutor
 import org.apache.commons.exec.PumpStreamHandler
@@ -35,6 +35,7 @@ import java.lang.NumberFormatException
 import java.nio.ByteBuffer
 import java.nio.ByteOrder
 import java.security.MessageDigest
+import java.util.*
 import java.util.regex.Pattern
 
 class Common {
@@ -78,7 +79,7 @@ class Common {
             val a = x shr 14
             val b = x - (a shl 14) shr 7
             val c = x and 0x7f
-            return String.format("%d.%d.%d", a, b, c)
+            return String.format(Locale.getDefault(), "%d.%d.%d", a, b, c)
         }
 
         fun packOsPatchLevel(x: String?): Int {
@@ -234,7 +235,7 @@ class Common {
 
         //using mkbootfs
         fun packRootfs(rootDir: String, ramdiskGz: String, osMajor: Int = 10) {
-            val mkbootfs = String.format(Helper.prop("mkbootfsBin"), osMajor)
+            val mkbootfs = String.format(Locale.getDefault(), Helper.prop("mkbootfsBin"), osMajor)
             log.info("Packing rootfs $rootDir ...")
             val outputStream = ByteArrayOutputStream()
             DefaultExecutor().let { exec ->
diff --git a/bbootimg/src/main/kotlin/bootimg/Signer.kt b/bbootimg/src/main/kotlin/bootimg/Signer.kt
index be17cf2..66b1106 100644
--- a/bbootimg/src/main/kotlin/bootimg/Signer.kt
+++ b/bbootimg/src/main/kotlin/bootimg/Signer.kt
@@ -24,7 +24,7 @@ import org.apache.commons.exec.CommandLine
 import org.apache.commons.exec.DefaultExecutor
 import org.slf4j.LoggerFactory
 import java.io.File
-import cfig.EnvironmentVerifier
+import cfig.utils.EnvironmentVerifier
 
 class Signer {
     companion object {
diff --git a/bbootimg/src/main/kotlin/bootimg/cpio/AndroidCpio.kt b/bbootimg/src/main/kotlin/bootimg/cpio/AndroidCpio.kt
index a272818..d390c38 100644
--- a/bbootimg/src/main/kotlin/bootimg/cpio/AndroidCpio.kt
+++ b/bbootimg/src/main/kotlin/bootimg/cpio/AndroidCpio.kt
@@ -15,16 +15,16 @@
 package cfig.bootimg.cpio
 
 import cfig.helper.Helper
-import cfig.EnvironmentVerifier
+import cfig.utils.EnvironmentVerifier
 import com.fasterxml.jackson.core.JsonParser
 import com.fasterxml.jackson.databind.ObjectMapper
 import org.apache.commons.compress.archivers.cpio.CpioArchiveInputStream
 import org.apache.commons.compress.archivers.cpio.CpioConstants
 import org.slf4j.LoggerFactory
 import java.io.*
-import java.nio.charset.Charset
 import java.nio.file.Files
 import java.nio.file.Paths
+import java.util.*
 import java.util.regex.Pattern
 
 class AndroidCpio {
@@ -213,7 +213,7 @@ class AndroidCpio {
                     name = entry.name,
                     statMode = entry.mode,
                     ino = entry.inode,
-                    note = String.format("%6s", java.lang.Long.toOctalString(entry.mode))
+                    note = String.format(Locale.getDefault(), "%6s", java.lang.Long.toOctalString(entry.mode))
                 )
                 if (!cis.canReadEntryData(entry)) {
                     throw RuntimeException("can not read entry ??")
@@ -224,7 +224,7 @@ class AndroidCpio {
                 if (((entry.mode and PERM_MASK).shr(7)).toInt() != 0b11) {
                     //@formatter:off
                     log.warn("  root/${entry.name} has improper file mode "
-                            + String.format("%03o, ", entry.mode and PERM_MASK) + "fix it"
+                            + String.format(Locale.getDefault(), "%03o, ", entry.mode and PERM_MASK) + "fix it"
                     )
                     //@formatter:on
                 }
diff --git a/bbootimg/src/main/kotlin/bootimg/cpio/NewAsciiCpio.kt b/bbootimg/src/main/kotlin/bootimg/cpio/NewAsciiCpio.kt
index 55e57e4..3467727 100644
--- a/bbootimg/src/main/kotlin/bootimg/cpio/NewAsciiCpio.kt
+++ b/bbootimg/src/main/kotlin/bootimg/cpio/NewAsciiCpio.kt
@@ -16,6 +16,7 @@ package cfig.bootimg.cpio
 
 import cfig.io.Struct3
 import org.apache.commons.compress.archivers.cpio.CpioConstants
+import java.util.*
 
 /*
     cpio "New ASCII Format" with 070701 as magic
@@ -38,26 +39,26 @@ class NewAsciiCpio(
 ) {
     init {
         if (SIZE != Struct3(FORMAT_STRING).calcSize()) {
-            throw RuntimeException()
+            throw RuntimeException("cpio format check failed")
         }
     }
 
     fun encode(): ByteArray {
         return Struct3(FORMAT_STRING).pack(
-            String.format("%s", c_magic),
-            String.format("%08x", c_ino),
-            String.format("%08x", c_mode),
-            String.format("%08x", c_uid),
-            String.format("%08x", c_gid),
-            String.format("%08x", c_nlink),
-            String.format("%08x", c_mtime),
-            String.format("%08x", c_filesize),
-            String.format("%08x", c_devmajor),
-            String.format("%08x", c_devminor),
-            String.format("%08x", c_rdevmajor),
-            String.format("%08x", c_rdevminor),
-            String.format("%08x", c_namesize),
-            String.format("%08x", c_check),
+            String.format(Locale.getDefault(), "%s", c_magic),
+            String.format(Locale.getDefault(), "%08x", c_ino),
+            String.format(Locale.getDefault(), "%08x", c_mode),
+            String.format(Locale.getDefault(),"%08x", c_uid),
+            String.format(Locale.getDefault(),"%08x", c_gid),
+            String.format(Locale.getDefault(),"%08x", c_nlink),
+            String.format(Locale.getDefault(),"%08x", c_mtime),
+            String.format(Locale.getDefault(),"%08x", c_filesize),
+            String.format(Locale.getDefault(),"%08x", c_devmajor),
+            String.format(Locale.getDefault(),"%08x", c_devminor),
+            String.format(Locale.getDefault(),"%08x", c_rdevmajor),
+            String.format(Locale.getDefault(),"%08x", c_rdevminor),
+            String.format(Locale.getDefault(),"%08x", c_namesize),
+            String.format(Locale.getDefault(),"%08x", c_check),
         )
     }
 
diff --git a/bbootimg/src/main/kotlin/bootimg/v2/BootV2.kt b/bbootimg/src/main/kotlin/bootimg/v2/BootV2.kt
index afb1c46..7ec0a4b 100644
--- a/bbootimg/src/main/kotlin/bootimg/v2/BootV2.kt
+++ b/bbootimg/src/main/kotlin/bootimg/v2/BootV2.kt
@@ -16,7 +16,7 @@ package cfig.bootimg.v2
 
 import avb.AVBInfo
 import cfig.Avb
-import cfig.EnvironmentVerifier
+import cfig.utils.EnvironmentVerifier
 import cfig.bootimg.Common
 import cfig.bootimg.Common.Companion.deleleIfExists
 import cfig.bootimg.Signer
diff --git a/bbootimg/src/main/kotlin/bootimg/v3/BootV3.kt b/bbootimg/src/main/kotlin/bootimg/v3/BootV3.kt
index c6aa3d4..2ae56ad 100644
--- a/bbootimg/src/main/kotlin/bootimg/v3/BootV3.kt
+++ b/bbootimg/src/main/kotlin/bootimg/v3/BootV3.kt
@@ -18,7 +18,7 @@ import avb.AVBInfo
 import avb.alg.Algorithms
 import avb.blob.AuxBlob
 import cfig.Avb
-import cfig.EnvironmentVerifier
+import cfig.utils.EnvironmentVerifier
 import cfig.bootimg.Common.Companion.deleleIfExists
 import cfig.bootimg.Common.Companion.getPaddingSize
 import cfig.bootimg.Signer
diff --git a/bbootimg/src/main/kotlin/bootimg/v3/VendorBoot.kt b/bbootimg/src/main/kotlin/bootimg/v3/VendorBoot.kt
index aae0749..9ed481e 100644
--- a/bbootimg/src/main/kotlin/bootimg/v3/VendorBoot.kt
+++ b/bbootimg/src/main/kotlin/bootimg/v3/VendorBoot.kt
@@ -16,7 +16,7 @@ package cfig.bootimg.v3
 
 import avb.AVBInfo
 import cfig.Avb
-import cfig.EnvironmentVerifier
+import cfig.utils.EnvironmentVerifier
 import cfig.bootimg.Common.Companion.deleleIfExists
 import cfig.bootimg.Signer
 import cfig.helper.Helper
@@ -73,7 +73,7 @@ data class VendorBoot(
                     PLATFORM.ordinal -> PLATFORM
                     RECOVERY.ordinal -> RECOVERY
                     DLKM.ordinal -> DLKM
-                    else -> throw IllegalArgumentException()
+                    else -> throw IllegalArgumentException("illegal VrtType $value")
                 }
             }
         }
diff --git a/bbootimg/src/main/kotlin/init/Reboot.kt b/bbootimg/src/main/kotlin/init/Reboot.kt
index 51b44ba..3cda74c 100644
--- a/bbootimg/src/main/kotlin/init/Reboot.kt
+++ b/bbootimg/src/main/kotlin/init/Reboot.kt
@@ -14,7 +14,7 @@
 
 package cfig.init
 
-import cfig.bootloader_message.BootloaderMsg
+import cfig.bcb.BootloaderMsg
 import org.slf4j.LoggerFactory
 import java.util.*
 
diff --git a/bbootimg/src/main/kotlin/packable/BootImgParser.kt b/bbootimg/src/main/kotlin/packable/BootImgParser.kt
index 89c654b..3968a41 100644
--- a/bbootimg/src/main/kotlin/packable/BootImgParser.kt
+++ b/bbootimg/src/main/kotlin/packable/BootImgParser.kt
@@ -26,7 +26,7 @@ import org.slf4j.LoggerFactory
 import java.io.File
 import java.io.FileInputStream
 
-class BootImgParser() : IPackable {
+class BootImgParser : IPackable {
     override val loopNo: Int
         get() = 0
     private val workDir = Helper.prop("workDir")
diff --git a/bbootimg/src/main/kotlin/packable/DtboParser.kt b/bbootimg/src/main/kotlin/packable/DtboParser.kt
index 3dc3bba..d52d8eb 100644
--- a/bbootimg/src/main/kotlin/packable/DtboParser.kt
+++ b/bbootimg/src/main/kotlin/packable/DtboParser.kt
@@ -15,10 +15,9 @@
 package cfig.packable
 
 import avb.blob.Footer
-import cfig.EnvironmentVerifier
-import cfig.dtb_util.DTC
+import cfig.utils.EnvironmentVerifier
+import cfig.utils.DTC
 import cfig.helper.Helper
-import cfig.Avb
 import com.fasterxml.jackson.databind.ObjectMapper
 import org.apache.commons.exec.CommandLine
 import org.apache.commons.exec.DefaultExecutor
@@ -46,7 +45,8 @@ class DtboParser(val workDir: File) : IPackable {
         cleanUp()
         val dtbPath = File("$outDir/dtb").path
         val headerPath = File("$outDir/dtbo.header").path
-        val cmd = CommandLine.parse("$dtboMaker dump $fileName").let {
+        val cmdPrefix = if (EnvironmentVerifier().isWindows) "python " else ""
+        val cmd = CommandLine.parse("$cmdPrefix$dtboMaker dump $fileName").let {
             it.addArguments("--dtb $dtbPath")
             it.addArguments("--output $headerPath")
         }
diff --git a/bbootimg/src/main/kotlin/packable/PackableLauncher.kt b/bbootimg/src/main/kotlin/packable/PackableLauncher.kt
index 74f2b75..0ff89ce 100644
--- a/bbootimg/src/main/kotlin/packable/PackableLauncher.kt
+++ b/bbootimg/src/main/kotlin/packable/PackableLauncher.kt
@@ -14,7 +14,7 @@
 
 package cfig.packable
 
-import cfig.sparse_util.SparseImgParser
+import cfig.utils.SparseImgParser
 import org.slf4j.LoggerFactory
 import java.io.File
 import java.util.regex.Pattern
diff --git a/bbootimg/src/main/kotlin/dtb_util/DTC.kt b/bbootimg/src/main/kotlin/utils/DTC.kt
similarity index 92%
rename from bbootimg/src/main/kotlin/dtb_util/DTC.kt
rename to bbootimg/src/main/kotlin/utils/DTC.kt
index 65f40b6..5ce1323 100644
--- a/bbootimg/src/main/kotlin/dtb_util/DTC.kt
+++ b/bbootimg/src/main/kotlin/utils/DTC.kt
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package cfig.dtb_util
+package cfig.utils
 
 import org.apache.commons.exec.CommandLine
 import org.apache.commons.exec.DefaultExecutor
@@ -23,7 +23,7 @@ class DTC {
 
     fun decompile(dtbFile: String, outFile: String): Boolean {
         log.info("parsing DTB: $dtbFile")
-        val cmd = CommandLine.parse("dtc -I dtb -O dts").let {
+        val cmd = CommandLine.parse("dtc -q -I dtb -O dts").let {
             it.addArguments("$dtbFile")
             it.addArguments("-o $outFile")
         }
@@ -46,7 +46,7 @@ class DTC {
 
     fun compile(dtsFile: String, outFile: String): Boolean {
         log.info("compiling DTS: $dtsFile")
-        val cmd = CommandLine.parse("dtc -I dts -O dtb").let {
+        val cmd = CommandLine.parse("dtc -q -I dts -O dtb").let {
             it.addArguments("$dtsFile")
             it.addArguments("-o $outFile")
         }
diff --git a/bbootimg/src/main/kotlin/EnvironmentVerifier.kt b/bbootimg/src/main/kotlin/utils/EnvironmentVerifier.kt
similarity index 99%
rename from bbootimg/src/main/kotlin/EnvironmentVerifier.kt
rename to bbootimg/src/main/kotlin/utils/EnvironmentVerifier.kt
index 8715c6c..62c5994 100644
--- a/bbootimg/src/main/kotlin/EnvironmentVerifier.kt
+++ b/bbootimg/src/main/kotlin/utils/EnvironmentVerifier.kt
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package cfig
+package cfig.utils
 
 import org.apache.commons.exec.CommandLine
 import org.apache.commons.exec.DefaultExecutor
diff --git a/bbootimg/src/main/kotlin/kernel_util/KernelExtractor.kt b/bbootimg/src/main/kotlin/utils/KernelExtractor.kt
similarity index 97%
rename from bbootimg/src/main/kotlin/kernel_util/KernelExtractor.kt
rename to bbootimg/src/main/kotlin/utils/KernelExtractor.kt
index f4eab1d..e1b2c06 100644
--- a/bbootimg/src/main/kotlin/kernel_util/KernelExtractor.kt
+++ b/bbootimg/src/main/kotlin/utils/KernelExtractor.kt
@@ -12,9 +12,8 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package cfig.kernel_util
+package cfig.utils
 
-import cfig.EnvironmentVerifier
 import cfig.helper.Helper
 import org.apache.commons.exec.CommandLine
 import org.apache.commons.exec.DefaultExecutor
diff --git a/bbootimg/src/main/kotlin/sparse_util/SparseImgParser.kt b/bbootimg/src/main/kotlin/utils/SparseImgParser.kt
similarity index 97%
rename from bbootimg/src/main/kotlin/sparse_util/SparseImgParser.kt
rename to bbootimg/src/main/kotlin/utils/SparseImgParser.kt
index df16de6..acd2800 100644
--- a/bbootimg/src/main/kotlin/sparse_util/SparseImgParser.kt
+++ b/bbootimg/src/main/kotlin/utils/SparseImgParser.kt
@@ -12,9 +12,8 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package cfig.sparse_util
+package cfig.utils
 
-import cfig.EnvironmentVerifier
 import cfig.packable.IPackable
 import org.slf4j.LoggerFactory
 import cfig.helper.Helper.Companion.check_call
@@ -22,7 +21,6 @@ import java.io.FileInputStream
 import java.io.File
 import com.fasterxml.jackson.databind.ObjectMapper
 import avb.blob.Footer
-import cfig.Avb
 
 class SparseImgParser : IPackable {
     override val loopNo: Int
diff --git a/bbootimg/src/test/kotlin/EnvironmentVerifierTest.kt b/bbootimg/src/test/kotlin/EnvironmentVerifierTest.kt
index 9fba771..50216ab 100644
--- a/bbootimg/src/test/kotlin/EnvironmentVerifierTest.kt
+++ b/bbootimg/src/test/kotlin/EnvironmentVerifierTest.kt
@@ -12,12 +12,9 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-import cfig.EnvironmentVerifier
+import cfig.utils.EnvironmentVerifier
 import org.junit.Test
 
-import org.junit.Assert.*
-import org.junit.Before
-
 class EnvironmentVerifierTest {
     private val envv = EnvironmentVerifier()
 
diff --git a/bbootimg/src/test/kotlin/ReadTest.kt b/bbootimg/src/test/kotlin/ReadTest.kt
index e3a507a..f72c60c 100644
--- a/bbootimg/src/test/kotlin/ReadTest.kt
+++ b/bbootimg/src/test/kotlin/ReadTest.kt
@@ -278,16 +278,20 @@ class ReadTest {
 
     fun String.executeCmd(inServices: MutableList<Service>,
                           inTriggers: List<Trigger>, inIndent: String) {
-        val aPre = inIndent + "  "
+        val aPre = "$inIndent  "
         if (this.startsWith("trigger ")) {
-            println(aPre + "|-- " + this)
+            println("$aPre|-- $this")
             queueEventTrigger(inServices, inTriggers, this.substring(8).trim(), aPre + "|  ")
         } else if (this.startsWith("chmod")) {
+            //ignore
         } else if (this.startsWith("chown")) {
+            //ignore
         } else if (this.startsWith("mkdir")) {
+            //ignore
         } else if (this.startsWith("write")) {
+            //ignore
         } else if (Pattern.compile("class_start\\s+\\S+").matcher(this).find()) {
-            println(aPre + "|-- " + this)
+            println("$aPre|-- $this")
             val m = Pattern.compile("class_start\\s+(\\S+)$").matcher(this)
             if (m.find()) {
                 inServices
@@ -304,15 +308,15 @@ class ReadTest {
             println("$aPre|-- $this")
             println("""$aPre|    \-- Starting ${this.substring(5).trim()}...""")
         } else {
-            println(aPre + "|-- " + this)
+            println("$aPre|-- $this")
         }
     }
 
     @Test
     fun parseTest() {
         System.out.println(System.getProperty("user.dir"))
-        var gTriggers: MutableList<Trigger> = mutableListOf()
-        var gServices: MutableList<Service> = mutableListOf()
+        val gTriggers: MutableList<Trigger> = mutableListOf()
+        val gServices: MutableList<Service> = mutableListOf()
 
         parseConfig("__temp/", "/init.rc", gTriggers, gServices)
         parseConfig("__temp/", "/system/etc/init", gTriggers, gServices)
diff --git a/bbootimg/src/test/kotlin/avb/FooterTest.kt b/bbootimg/src/test/kotlin/avb/FooterTest.kt
index 0329dfb..a4afb9a 100644
--- a/bbootimg/src/test/kotlin/avb/FooterTest.kt
+++ b/bbootimg/src/test/kotlin/avb/FooterTest.kt
@@ -44,6 +44,7 @@ class FooterTest {
                 Footer(it)
                 assertEquals("Should never reach here", true, false)
             } catch (e: IllegalArgumentException) {
+                //expected
             }
         }
     }
diff --git a/bbootimg/src/test/kotlin/avb/alg/AlgorithmTest.kt b/bbootimg/src/test/kotlin/avb/alg/AlgorithmTest.kt
deleted file mode 100644
index 99d448b..0000000
--- a/bbootimg/src/test/kotlin/avb/alg/AlgorithmTest.kt
+++ /dev/null
@@ -1,27 +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 avb.alg
-
-import org.junit.Test
-
-import org.junit.Assert.*
-import java.nio.ByteBuffer
-
-class AlgorithmTest {
-
-    @Test
-    fun getName() {
-    }
-}
\ No newline at end of file
diff --git a/bbootimg/src/test/kotlin/avb/alg/AlgorithmsTest.kt b/bbootimg/src/test/kotlin/avb/alg/AlgorithmsTest.kt
index fad3c8a..5790e87 100644
--- a/bbootimg/src/test/kotlin/avb/alg/AlgorithmsTest.kt
+++ b/bbootimg/src/test/kotlin/avb/alg/AlgorithmsTest.kt
@@ -21,10 +21,10 @@ import org.junit.Test
 class AlgorithmsTest {
     @Test
     fun test1() {
-       val alg = Algorithms.get("NONE")!!
-
-        Assert.assertEquals(Helper.toHexString(Algorithms.get("SHA256_RSA4096")!!.padding),
-                "0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff003031300d060960864801650304020105000420")
-        println(alg)
+        Assert.assertEquals(
+            Helper.toHexString(Algorithms.get("SHA256_RSA4096")!!.padding),
+            "0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff003031300d060960864801650304020105000420"
+        )
+        println(Algorithms.get("NONE")!!)
     }
 }
diff --git a/bbootimg/src/test/kotlin/bootloader_message/BootloaderMsgTest.kt b/bbootimg/src/test/kotlin/bcb/BootloaderMsgTest.kt
similarity index 96%
rename from bbootimg/src/test/kotlin/bootloader_message/BootloaderMsgTest.kt
rename to bbootimg/src/test/kotlin/bcb/BootloaderMsgTest.kt
index c313559..e0d365c 100644
--- a/bbootimg/src/test/kotlin/bootloader_message/BootloaderMsgTest.kt
+++ b/bbootimg/src/test/kotlin/bcb/BootloaderMsgTest.kt
@@ -12,10 +12,10 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package bootloader_message
+package bcb
 
+import cfig.bcb.BootloaderMsg
 import cfig.bootimg.Common.Companion.deleleIfExists
-import cfig.bootloader_message.BootloaderMsg
 import org.junit.After
 import org.junit.Test
 import org.slf4j.LoggerFactory
diff --git a/bbootimg/src/test/kotlin/bcb/VirtualABMsgTest.kt b/bbootimg/src/test/kotlin/bcb/VirtualABMsgTest.kt
new file mode 100644
index 0000000..70c4386
--- /dev/null
+++ b/bbootimg/src/test/kotlin/bcb/VirtualABMsgTest.kt
@@ -0,0 +1,37 @@
+package bcb
+
+import cfig.bcb.VirtualABMsg
+import cfig.bootimg.Common.Companion.deleleIfExists
+import cfig.helper.Helper.Companion.check_call
+import org.junit.After
+import org.junit.Before
+
+import org.junit.Ignore
+import org.junit.Test
+import org.slf4j.LoggerFactory
+import java.io.File
+import java.io.FileInputStream
+
+class VirtualABMsgTest {
+    private val log = LoggerFactory.getLogger(VirtualABMsgTest::class.java)
+
+    @Before
+    fun setUp() {
+        "adb root".check_call()
+        "adb wait-for-device".check_call()
+        "adb shell dd if=/dev/block/by-name/misc of=/data/vendor/debug.misc skip=512 bs=64 count=1".check_call()
+        "adb pull /data/vendor/debug.misc".check_call()
+    }
+
+    @Test
+    @Ignore
+    fun parseVAB() {
+        val vab = VirtualABMsg(FileInputStream("debug.misc"))
+        log.info("VAB msg: $vab")
+    }
+
+    @After
+    fun tearDown() {
+        File("debug.misc").deleleIfExists()
+    }
+}
\ No newline at end of file
diff --git a/bbootimg/src/test/kotlin/init/RebootTest.kt b/bbootimg/src/test/kotlin/init/RebootTest.kt
index ee56430..c48c3d4 100644
--- a/bbootimg/src/test/kotlin/init/RebootTest.kt
+++ b/bbootimg/src/test/kotlin/init/RebootTest.kt
@@ -14,11 +14,11 @@
 
 package init
 
+import cfig.bcb.BootloaderMsg
 import org.junit.Test
 import org.junit.After
 import java.io.File
 import java.util.*
-import cfig.bootloader_message.BootloaderMsg
 import cfig.init.Reboot
 import cfig.bootimg.Common.Companion.deleleIfExists
 import org.slf4j.LoggerFactory
diff --git a/helper/build.gradle.kts b/helper/build.gradle.kts
index 5a22dae..02df4fe 100644
--- a/helper/build.gradle.kts
+++ b/helper/build.gradle.kts
@@ -15,7 +15,7 @@
 import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
 
 plugins {
-    id("org.jetbrains.kotlin.jvm") version "1.5.30"
+    id("org.jetbrains.kotlin.jvm") version "1.5.31"
     `java-library`
 }
 
@@ -49,5 +49,5 @@ dependencies {
 
 tasks.withType<KotlinCompile>().all {
     kotlinOptions.freeCompilerArgs += "-Xopt-in=kotlin.RequiresOptIn"
-    kotlinOptions.jvmTarget = "1.8"
+    kotlinOptions.jvmTarget = "11"
 }
diff --git a/helper/src/main/kotlin/cfig/helper/Helper.kt b/helper/src/main/kotlin/cfig/helper/Helper.kt
index d65f195..69e791c 100644
--- a/helper/src/main/kotlin/cfig/helper/Helper.kt
+++ b/helper/src/main/kotlin/cfig/helper/Helper.kt
@@ -369,6 +369,20 @@ class Helper {
             return String.format("%.1f %ciB", value / 1024.0, ci.current())
         }
 
+        fun readFully(fileName: String, offset: Long, byteCount: Int): ByteArray {
+            val data = ByteArray(byteCount).apply {
+                FileInputStream(fileName).use { fis ->
+                    fis.skip(offset)
+                    fis.read(this)
+                }
+            }
+            return data
+        }
+
+        fun readFully(fileName: String, coordinate: Pair<Long, Int>): ByteArray {
+            return readFully(fileName, coordinate.first, coordinate.second)
+        }
+
         private val log = LoggerFactory.getLogger("Helper")
     }
 }
diff --git a/helper/src/test/kotlin/cfig/io/Struct3Test.kt b/helper/src/test/kotlin/cfig/io/Struct3Test.kt
index 96c3e9e..dcbceba 100644
--- a/helper/src/test/kotlin/cfig/io/Struct3Test.kt
+++ b/helper/src/test/kotlin/cfig/io/Struct3Test.kt
@@ -19,6 +19,7 @@ import org.junit.Assert
 import org.junit.Test
 import java.io.ByteArrayInputStream
 
+@OptIn(kotlin.ExperimentalUnsignedTypes::class)
 class Struct3Test {
     private fun getConvertedFormats(inStruct: Struct3): ArrayList<Map<String, Int>> {
         val f = inStruct.javaClass.getDeclaredField("formats")