From c829cfcd593cb609c765a80bb1501e04cbab8ca9 Mon Sep 17 00:00:00 2001 From: Philippe PITTOLI Date: Fri, 21 Jun 2024 13:28:45 +0200 Subject: [PATCH] Hexa bindings: first commit. --- .gitignore | 10 +++++++ README.md | 37 +++++++++++++++++++++++++ examples/example.cr | 12 ++++++++ examples/makefile | 13 +++++++++ examples/makefile.local | 9 ++++++ makefile | 11 ++++++++ shard.yml | 15 ++++++++++ src/bindings.cr | 5 ++++ src/hexa.cr | 2 ++ src/high-level-bindings.cr | 57 ++++++++++++++++++++++++++++++++++++++ 10 files changed, 171 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 examples/example.cr create mode 100644 examples/makefile create mode 100644 examples/makefile.local create mode 100644 makefile create mode 100644 shard.yml create mode 100644 src/bindings.cr create mode 100644 src/hexa.cr create mode 100644 src/high-level-bindings.cr diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..168645d --- /dev/null +++ b/.gitignore @@ -0,0 +1,10 @@ +/docs/ +/lib/ +/bin/ +/.shards/ +/examples/example +*.dwarf + +# Libraries don't need dependency lock +# Dependencies will be locked in applications that use them +/shard.lock diff --git a/README.md b/README.md new file mode 100644 index 0000000..89d867d --- /dev/null +++ b/README.md @@ -0,0 +1,37 @@ +# hexa + +Bindings to `libhexa` to produce hexadecimal dumps of arbitrary input bytes. +This prints debug info in a pretty way. + +## Installation + +1. Add the dependency to your `shard.yml`: + + ```yaml + dependencies: + hexa: + branch: master + git: https://git.baguette.netlib.re/Baguette/hexa.cr.git + ``` + +2. Run `shards install` + +## Usage + +```crystal +require "hexa" + +h = Hexa.new 5_000 # Size of the output buffer. + +# First, an hexadecimal dump of a small text. +text = "hello this is some text" # could be Bytes +puts h.dump text + +# With a centered title on the first line. +title = "itz mai title lul" +puts h.dump title, text +``` + +## Contributors + +- [Philippe PITTOLI](https://github.com/your-github-user) - creator and maintainer diff --git a/examples/example.cr b/examples/example.cr new file mode 100644 index 0000000..f0b5afc --- /dev/null +++ b/examples/example.cr @@ -0,0 +1,12 @@ +require "../src/hexa.cr" + +h = Hexa.new 2_000 + +text = "hello this is some text I want to show" +puts h.dump text + +puts "" +puts "with a title:" + +title = "some text" +puts h.dump title, text diff --git a/examples/makefile b/examples/makefile new file mode 100644 index 0000000..8aaf0c1 --- /dev/null +++ b/examples/makefile @@ -0,0 +1,13 @@ +all: build + +include makefile.local + +SOURCE_FILES = ../src/bindings.cr ../src/hexa.cr ../src/high-level-bindings.cr + +example: $(SOURCE_FILES) example.cr + crystal build --progress $(LD_FLAGS) example.cr + +build: example + +run: build + $(LIB_PATH) ./example diff --git a/examples/makefile.local b/examples/makefile.local new file mode 100644 index 0000000..e036764 --- /dev/null +++ b/examples/makefile.local @@ -0,0 +1,9 @@ +ifdef DEV +# Use ABSOLUTE paths for linker parameters (-L path) to avoid errors. +LIB_HEXA_REPOS ?= /tmp/prog/libhexa/zig-out/lib +LIB_PATH = LD_LIBRARY_PATH=$(LIB_HEXA_REPOS) +endif +ifdef LIB_HEXA_REPOS +# This is an example on how to use link flags with Crystal. +LD_FLAGS ?= --link-flags "-L$(LIB_HEXA_REPOS)" +endif diff --git a/makefile b/makefile new file mode 100644 index 0000000..cb4f2bd --- /dev/null +++ b/makefile @@ -0,0 +1,11 @@ +SOURCE_FILES = src/bindings.cr src/hexa.cr src/high-level-bindings.cr + +doc: + crystal docs $(SOURCE_FILES) + +HTTPD_ACCESS_LOGS ?= /tmp/access-hexa.cr-docs.log +HTTPD_ADDR ?= 127.0.0.1 +HTTPD_PORT ?= 9002 +DIR ?= docs +serve-doc: + darkhttpd $(DIR) --addr $(HTTPD_ADDR) --port $(HTTPD_PORT) --log $(HTTPD_ACCESS_LOGS) diff --git a/shard.yml b/shard.yml new file mode 100644 index 0000000..74a2e98 --- /dev/null +++ b/shard.yml @@ -0,0 +1,15 @@ +name: hexa +version: 0.1.0 + +authors: + - Philippe PITTOLI + +description: | + High-level Crystal bindings to libhexa. + +crystal: '>= 1.12.2' + +libraries: + libhexa: ">= 0.1.0" + +license: ISC diff --git a/src/bindings.cr b/src/bindings.cr new file mode 100644 index 0000000..974c3f6 --- /dev/null +++ b/src/bindings.cr @@ -0,0 +1,5 @@ +@[Link("hexa")] +lib LibHexa + # title & title_len, input & input len, buffer & pointer on buffer len -> int + fun dump = hexdump(LibC::Char*, UInt32, LibC::Char*, UInt32, LibC::Char*, UInt32*) : LibC::Int +end diff --git a/src/hexa.cr b/src/hexa.cr new file mode 100644 index 0000000..3ae0a21 --- /dev/null +++ b/src/hexa.cr @@ -0,0 +1,2 @@ +require "./bindings.cr" +require "./high-level-bindings.cr" diff --git a/src/high-level-bindings.cr b/src/high-level-bindings.cr new file mode 100644 index 0000000..264b6af --- /dev/null +++ b/src/high-level-bindings.cr @@ -0,0 +1,57 @@ +# The `Hexa` class is a high-level binding to `libhexa`, producing hexadecimal dumps of arbitrary input bytes. +# Used to print debug info in a pretty way. +# +# This library can be used with either raw Bytes or strings for the input buffer. +# A title can be given to the dump. +# +# ``` +# require "hexa" +# +# h = Hexa.new 2_000 # Size of the output buffer. +# +# text = "hello this is some text I want to show" +# puts h.dump text +# +# puts "" +# puts "same thing with a title:" +# +# title = "some text" +# puts h.dump title, text +# ``` +class Hexa + property buffer_size : UInt32 = 200_000 + def initialize(buffer_size : UInt32?) + @buffer_size = buffer_size if buffer_size + @output_buffer = Array(UInt8).new @buffer_size + end + + # Hexdump with a title and an input string. + def dump(title : String, buffer : String) : String + dump title, buffer.to_slice + end + + # Hexdump with a title and raw bytes as input. + def dump(title : String, buffer : Bytes) : String + buflen : UInt32 = @buffer_size + ret = LibHexa.dump title, title.size, buffer.to_unsafe, buffer.size, @output_buffer.to_unsafe, pointerof(buflen) + if ret != 0 + raise "oh noes, 'dump' iz brkn" + end + String.new @output_buffer.to_unsafe.to_slice(buflen) + end + + # Hexdump a string (no title). + def dump(buffer : String) : String + dump buffer.to_slice + end + + # Hexdump raw bytes (no title). + def dump(buffer : Bytes) : String + buflen : UInt32 = @buffer_size + ret = LibHexa.dump "", 0, buffer.to_unsafe, buffer.size, @output_buffer.to_unsafe, pointerof(buflen) + if ret != 0 + raise "oh noes, 'dump' iz brkn" + end + String.new @output_buffer.to_unsafe.to_slice(buflen) + end +end