Start repo, claude & kimi still vibing tho
This commit is contained in:
134
lib/odinsea/util/bit_tools.ex
Normal file
134
lib/odinsea/util/bit_tools.ex
Normal file
@@ -0,0 +1,134 @@
|
||||
defmodule Odinsea.Util.BitTools do
|
||||
@moduledoc """
|
||||
Utility functions for bit and byte manipulation.
|
||||
Provides helper functions for working with binary data, similar to Java's BitTools.
|
||||
|
||||
Ported from: src/tools/BitTools.java
|
||||
"""
|
||||
|
||||
use Bitwise
|
||||
|
||||
@doc """
|
||||
Reads a 16-bit short integer (little-endian) from a byte array at the given index.
|
||||
|
||||
## Parameters
|
||||
- array: Binary array
|
||||
- index: Starting position (0-based)
|
||||
|
||||
## Returns
|
||||
- 16-bit integer value (0-65535)
|
||||
"""
|
||||
@spec get_short(binary(), non_neg_integer()) :: non_neg_integer()
|
||||
def get_short(array, index) when is_binary(array) do
|
||||
<<_skip::binary-size(index), value::little-unsigned-16, _rest::binary>> = array
|
||||
value
|
||||
end
|
||||
|
||||
@doc """
|
||||
Reads a string from a byte array at the given index with specified length.
|
||||
|
||||
## Parameters
|
||||
- array: Binary array
|
||||
- index: Starting position
|
||||
- length: Number of bytes to read
|
||||
|
||||
## Returns
|
||||
- String extracted from the byte array
|
||||
"""
|
||||
@spec get_string(binary(), non_neg_integer(), non_neg_integer()) :: String.t()
|
||||
def get_string(array, index, length) when is_binary(array) do
|
||||
<<_skip::binary-size(index), string_data::binary-size(length), _rest::binary>> = array
|
||||
to_string(string_data)
|
||||
end
|
||||
|
||||
@doc """
|
||||
Reads a MapleStory-convention string from a byte array.
|
||||
Format: 2-byte little-endian length prefix + string data
|
||||
|
||||
## Parameters
|
||||
- array: Binary array
|
||||
- index: Starting position
|
||||
|
||||
## Returns
|
||||
- String extracted from the byte array
|
||||
"""
|
||||
@spec get_maple_string(binary(), non_neg_integer()) :: String.t()
|
||||
def get_maple_string(array, index) when is_binary(array) do
|
||||
length = get_short(array, index)
|
||||
get_string(array, index + 2, length)
|
||||
end
|
||||
|
||||
@doc """
|
||||
Rotates bits of a byte left by count positions.
|
||||
|
||||
## Parameters
|
||||
- byte_val: Byte value (0-255)
|
||||
- count: Number of positions to rotate
|
||||
|
||||
## Returns
|
||||
- Rotated byte value
|
||||
"""
|
||||
@spec roll_left(byte(), non_neg_integer()) :: byte()
|
||||
def roll_left(byte_val, count) when is_integer(byte_val) and byte_val >= 0 and byte_val <= 255 do
|
||||
tmp = byte_val &&& 0xFF
|
||||
rotated = tmp <<< rem(count, 8)
|
||||
((rotated &&& 0xFF) ||| (rotated >>> 8)) &&& 0xFF
|
||||
end
|
||||
|
||||
@doc """
|
||||
Rotates bits of a byte right by count positions.
|
||||
|
||||
## Parameters
|
||||
- byte_val: Byte value (0-255)
|
||||
- count: Number of positions to rotate
|
||||
|
||||
## Returns
|
||||
- Rotated byte value
|
||||
"""
|
||||
@spec roll_right(byte(), non_neg_integer()) :: byte()
|
||||
def roll_right(byte_val, count) when is_integer(byte_val) and byte_val >= 0 and byte_val <= 255 do
|
||||
tmp = byte_val &&& 0xFF
|
||||
rotated = (tmp <<< 8) >>> rem(count, 8)
|
||||
((rotated &&& 0xFF) ||| (rotated >>> 8)) &&& 0xFF
|
||||
end
|
||||
|
||||
@doc """
|
||||
Repeats the first `count` bytes of `input` `mul` times.
|
||||
|
||||
## Parameters
|
||||
- input: Binary input
|
||||
- count: Number of bytes to repeat from the input
|
||||
- mul: Number of times to repeat
|
||||
|
||||
## Returns
|
||||
- Binary with repeated bytes
|
||||
"""
|
||||
@spec multiply_bytes(binary(), non_neg_integer(), non_neg_integer()) :: binary()
|
||||
def multiply_bytes(input, count, mul) when is_binary(input) do
|
||||
# Take first `count` bytes
|
||||
chunk = binary_part(input, 0, min(count, byte_size(input)))
|
||||
|
||||
# Repeat `mul` times
|
||||
1..mul
|
||||
|> Enum.map(fn _ -> chunk end)
|
||||
|> IO.iodata_to_binary()
|
||||
end
|
||||
|
||||
@doc """
|
||||
Converts a double-precision float to a short by extracting high bits.
|
||||
|
||||
## Parameters
|
||||
- d: Double-precision float
|
||||
|
||||
## Returns
|
||||
- 16-bit integer extracted from the high bits
|
||||
"""
|
||||
@spec double_to_short_bits(float()) :: integer()
|
||||
def double_to_short_bits(d) when is_float(d) do
|
||||
# Convert double to 64-bit integer representation
|
||||
<<long_bits::signed-64>> = <<d::float>>
|
||||
|
||||
# Extract high 16 bits (shift right by 48)
|
||||
(long_bits >>> 48) &&& 0xFFFF
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user