minglipro 2db24530d6
feat(bytes): 添加ByteBuffer工具类和ByteFlags数据结构
- 新增ByteBufferUtils.kt文件,提供字符串、布尔值、位标志等类型的读写扩展函数
- 新增ByteFlags.kt文件,实现8位布尔标志集合的数据结构和位操作功能
- 添加putString/getString方法支持C风格字符串的null终止符处理
- 实现ByteFlags的位操作功能,包括AND、OR、XOR、NOT等运算
- 添加二进制字符串、十六进制字符串的转换和格式化输出功能
- 移除NettyUtils中重复的toByteBuffer扩展函数
- 更新项目版本号从4.2.6到4.2.7
2026-01-07 10:07:48 +08:00

206 lines
6.0 KiB
Kotlin
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* Copyright 2026 mingliqiye
*
* 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.
*
* ProjectName mingli-utils
* ModuleName mingli-utils.main
* CurrentFile ByteBufferUtils.kt
* LastUpdate 2026-01-07 10:01:45
* UpdateUser MingLiPro
*/
@file:JvmName("ByteBufferUtil")
package com.mingliqiye.utils.bytes
import java.nio.ByteBuffer
import java.nio.charset.Charset
/**
* 将字符串以指定字符集编码后写入 [ByteBuffer],并在末尾追加一个空字节(`0x00`)作为字符串终止符。
*
* 此方法适用于需要 C 风格字符串null-terminated string的协议或场景。
*
* @param string 要写入的字符串,不可为 null
* @param charset 字符编码,默认为 [Charsets.UTF_8]
* @return 当前 [ByteBuffer] 实例(支持链式调用)
*/
fun ByteBuffer.putString(string: String, charset: Charset = Charsets.UTF_8): ByteBuffer =
this.put(string.toByteArray(charset)).put(0x00)
/**
* 从 [ByteBuffer] 中读取一个以空字节(`0x00`)结尾的字符串。
*
* 该方法会持续读取字节,直到遇到第一个 `0x00`null terminator为止并将之前读取的字节按指定字符集解码为字符串。
* **注意**此操作会修改缓冲区的位置position且不处理缓冲区越界情况若无终止符会抛出异常
*
* @param charset 字符编码,默认为 [Charsets.UTF_8]
* @return 解码后的字符串(不含终止符)
* @throws BufferUnderflowException 如果缓冲区中没有足够的字节(即未找到终止符)
*/
fun ByteBuffer.getString(charset: Charset = Charsets.UTF_8): String {
val data = ArrayList<Byte>()
while (true) {
val byte = this.get()
if (byte == 0x00.toByte()) {
break
}
data.add(byte)
}
return String(data.toByteArray(), charset)
}
/**
* 将 [ByteBuffer] 中剩余的全部字节读取为一个 [ByteArray]。
*
* 此方法会读取从当前位置到 limit 之间的所有字节,并推进 position。
*
* @return 包含剩余字节的新字节数组
*/
fun ByteBuffer.toByteArray(): ByteArray {
val ba = ByteArray(this.remaining())
this.get(ba)
return ba
}
/**
* 将一个布尔列表(长度必须为 8转换为 [ByteFlags] 并写入 [ByteBuffer]。
*
* 列表索引 0~7 分别对应位 b0~b7b0 为最低有效位)。
*
* @param bit 长度为 8 的布尔列表,表示 8 个位的状态
* @return 当前 [ByteBuffer] 实例(支持链式调用)
* @throws IndexOutOfBoundsException 如果列表长度不足 8
*/
fun ByteBuffer.putByteFlags(
bit: List<Boolean> = List(8) { false },
): ByteBuffer = this.putByteFlags(
ByteFlags(
bit[0],
bit[1],
bit[2],
bit[3],
bit[4],
bit[5],
bit[6],
bit[7],
)
)
/**
* 将一个布尔数组(长度必须为 8转换为 [ByteFlags] 并写入 [ByteBuffer]。
*
* 数组索引 0~7 分别对应位 b0~b7b0 为最低有效位)。
*
* @param bit 长度为 8 的布尔数组
* @return 当前 [ByteBuffer] 实例(支持链式调用)
* @throws IndexOutOfBoundsException 如果数组长度不足 8
*/
fun ByteBuffer.putByteFlags(
bit: BooleanArray = BooleanArray(8),
): ByteBuffer = this.putByteFlags(
ByteFlags(
bit[0],
bit[1],
bit[2],
bit[3],
bit[4],
bit[5],
bit[6],
bit[7],
)
)
/**
* 将 [ByteFlags] 对象转换为字节并写入 [ByteBuffer]。
*
* @param byteFlags 要写入的位标志对象
* @return 当前 [ByteBuffer] 实例(支持链式调用)
*/
fun ByteBuffer.putByteFlags(byteFlags: ByteFlags): ByteBuffer = this.put(byteFlags.toByte())
/**
* 通过 8 个独立的布尔参数构造 [ByteFlags] 并写入 [ByteBuffer]。
*
* 参数顺序:`bit0`LSB到 `bit7`MSB
*
* @param bit0 第 0 位(最低位)
* @param bit1 第 1 位
* @param bit2 第 2 位
* @param bit3 第 3 位
* @param bit4 第 4 位
* @param bit5 第 5 位
* @param bit6 第 6 位
* @param bit7 第 7 位(最高位)
* @return 当前 [ByteBuffer] 实例(支持链式调用)
*/
fun ByteBuffer.putByteFlags(
bit0: Boolean = false,
bit1: Boolean = false,
bit2: Boolean = false,
bit3: Boolean = false,
bit4: Boolean = false,
bit5: Boolean = false,
bit6: Boolean = false,
bit7: Boolean = false,
): ByteBuffer = this.putByteFlags(
ByteFlags(
bit0,
bit1,
bit2,
bit3,
bit4,
bit5,
bit6,
bit7,
)
)
/**
* 从 [ByteBuffer] 中读取一个字节,并将其解析为 [ByteFlags] 对象。
*
* @return 表示该字节各位状态的 [ByteFlags] 实例
*/
fun ByteBuffer.getByteFlags(): ByteFlags = ByteFlags(this.get())
/**
* 从 [ByteBuffer] 中读取一个字节,并将其解释为布尔值。
*
* 约定:`0x01` 表示 `true`,其他值(包括 `0x00`)均视为 `false`。
*
* @return 布尔值
*/
fun ByteBuffer.getBoolean(): Boolean = this.get() == 0x01.toByte()
/**
* 将布尔值写入 [ByteBuffer]。
*
* 约定:`true` 写为 `0x01``false` 写为 `0x00`。
*
* @param boolean 要写入的布尔值
* @return 当前 [ByteBuffer] 实例(支持链式调用)
*/
fun ByteBuffer.putBoolean(boolean: Boolean): ByteBuffer = this.put(if (boolean) 0x01 else 0x00)
/**
* 将当前字节数组包装为一个只读的 [ByteBuffer]。
*
* 使用 [ByteBuffer.wrap] 创建position 初始为 0limit 为数组长度。
*
* @return 包装后的 [ByteBuffer] 实例
*/
fun ByteArray.toByteBuffer(): ByteBuffer {
return ByteBuffer.wrap(this)
}