Start repo, claude & kimi still vibing tho

This commit is contained in:
ra
2026-02-14 17:04:21 -07:00
commit f5b8aeb39d
54 changed files with 9466 additions and 0 deletions

171
lib/odinsea/net/hex.ex Normal file
View File

@@ -0,0 +1,171 @@
defmodule Odinsea.Net.Hex do
@moduledoc """
Hex encoding/decoding utilities ported from Java HexTool.
"""
@doc """
Converts a binary to a hex string (space-separated bytes).
## Examples
iex> Odinsea.Net.Hex.encode(<<0x01, 0xAB, 0xFF>>)
"01 AB FF"
"""
@spec encode(binary()) :: String.t()
def encode(<<>>), do: ""
def encode(binary) when is_binary(binary) do
binary
|> :binary.bin_to_list()
|> Enum.map(&byte_to_hex/1)
|> Enum.join(" ")
end
@doc """
Converts a binary to a hex string (no spaces).
## Examples
iex> Odinsea.Net.Hex.to_string_compact(<<0x01, 0xAB, 0xFF>>)
"01ABFF"
"""
@spec to_string_compact(binary()) :: String.t()
def to_string_compact(<<>>), do: ""
def to_string_compact(binary) when is_binary(binary) do
binary
|> :binary.bin_to_list()
|> Enum.map(&byte_to_hex/1)
|> Enum.join()
end
@doc """
Converts a binary to a hex string with ASCII representation.
## Examples
iex> Odinsea.Net.Hex.to_pretty_string(<<0x48, 0x65, 0x6C, 0x6C, 0x6F>>)
"48 65 6C 6C 6F | Hello"
"""
@spec to_pretty_string(binary()) :: String.t()
def to_pretty_string(binary) when is_binary(binary) do
hex_part = encode(binary)
ascii_part = to_ascii(binary)
"#{hex_part} | #{ascii_part}"
end
@doc """
Converts a hex string to binary.
## Examples
iex> Odinsea.Net.Hex.from_string("01 AB FF")
<<0x01, 0xAB, 0xFF>>
"""
@spec from_string(String.t()) :: binary()
def from_string(hex_string) when is_binary(hex_string) do
hex_string
|> String.replace(~r/\s+/, "")
|> String.downcase()
|> do_from_string()
end
defp do_from_string(<<>>), do: <<>>
defp do_from_string(<<hex1, hex2, rest::binary>>) do
byte = hex_to_byte(<<hex1, hex2>>)
<<byte, do_from_string(rest)::binary>>
end
defp do_from_string(<<_>>), do: raise(ArgumentError, "Invalid hex string length")
@doc """
Converts a byte to its 2-character hex representation.
"""
@spec byte_to_hex(byte()) :: String.t()
def byte_to_hex(byte) when is_integer(byte) and byte >= 0 and byte <= 255 do
byte
|> Integer.to_string(16)
|> String.pad_leading(2, "0")
|> String.upcase()
end
@doc """
Converts a 2-character hex string to a byte.
"""
@spec hex_to_byte(String.t()) :: byte()
def hex_to_byte(<<hex1, hex2>>) do
parse_hex_digit(hex1) * 16 + parse_hex_digit(hex2)
end
defp parse_hex_digit(?0), do: 0
defp parse_hex_digit(?1), do: 1
defp parse_hex_digit(?2), do: 2
defp parse_hex_digit(?3), do: 3
defp parse_hex_digit(?4), do: 4
defp parse_hex_digit(?5), do: 5
defp parse_hex_digit(?6), do: 6
defp parse_hex_digit(?7), do: 7
defp parse_hex_digit(?8), do: 8
defp parse_hex_digit(?9), do: 9
defp parse_hex_digit(?a), do: 10
defp parse_hex_digit(?b), do: 11
defp parse_hex_digit(?c), do: 12
defp parse_hex_digit(?d), do: 13
defp parse_hex_digit(?e), do: 14
defp parse_hex_digit(?f), do: 15
defp parse_hex_digit(_), do: raise(ArgumentError, "Invalid hex digit")
@doc """
Converts a binary to its ASCII representation (non-printable chars as dots).
"""
@spec to_ascii(binary()) :: String.t()
def to_ascii(<<>>), do: ""
def to_ascii(<<byte, rest::binary>>) do
char = if byte >= 32 and byte <= 126, do: <<byte>>, else: <<".">>
char <> to_ascii(rest)
end
@doc """
Converts a short (2 bytes) to a hex string.
"""
@spec short_to_hex(integer()) :: String.t()
def short_to_hex(value) when is_integer(value) do
<<value::signed-integer-little-16>>
|> encode()
end
@doc """
Converts an int (4 bytes) to a hex string.
"""
@spec int_to_hex(integer()) :: String.t()
def int_to_hex(value) when is_integer(value) do
<<value::signed-integer-little-32>>
|> encode()
end
@doc """
Formats a binary as a hex dump with offsets.
"""
@spec hex_dump(binary(), non_neg_integer()) :: String.t()
def hex_dump(binary, offset \\ 0) do
binary
|> :binary.bin_to_list()
|> Enum.chunk_every(16)
|> Enum.with_index()
|> Enum.map(fn {chunk, idx} ->
offset_str = Integer.to_string(offset + idx * 16, 16) |> String.pad_leading(8, "0")
hex_str = format_chunk(chunk)
ascii_str = to_ascii(:binary.list_to_bin(chunk))
"#{offset_str} #{hex_str} |#{ascii_str}|"
end)
|> Enum.join("\n")
end
defp format_chunk(chunk) do
chunk
|> Enum.map(&byte_to_hex/1)
|> Enum.map(&String.pad_trailing(&1, 2))
|> Enum.chunk_every(8)
|> Enum.map(&Enum.join(&1, " "))
|> Enum.join(" ")
|> String.pad_trailing(48)
end
end