diff options
| -rw-r--r-- | README.md | 33 | ||||
| -rw-r--r-- | zig-tlv-encoding/Makefile | 2 | ||||
| -rw-r--r-- | zig-tlv-encoding/main.zig | 97 |
3 files changed, 116 insertions, 16 deletions
@@ -16,22 +16,23 @@ running it. > also written in the most explicit way and lacks massively when it > comes to checking of errors etc. -| Example | Compiler | What does it do? | -|----------------------------------|------------|----------------------------------------------------------------| -| [c-asm](./c-asm) | clang-17 | Calls a function written in ASM from C code. | -| [c-embed](./c-embed) | clang-17 | Embedding external resources in compiled binary. | -| [c-signals](./c-signals) | clang-17 | Uses SIGUSR1 and SIGUSR2 as IPC mechanism. | -| [c-structs](./c-structs) | clang-17 | Saves and reads structs in/from binary files. | -| [zig-c-interop](./zig-c-interop) | zig-0.11.0 | Uses functions written in C from Zig code. | -| [zig-ppm](./zig-ppm) | zig-0.11.0 | Creates an image with random pixels in PPM image format. | -| [zig-structs](./zig-structs) | zig-0.11.0 | Serialization of a struct into JSON and then reading it back. | -| [zig-telnet](./zig-telnet) | zig-0.11.0 | Connects to Redis server like it is a basic telnet server. | -| [zig-x11](./zig-x11) | zig-0.11.0 | Uses X11 to create a basic window without any bindings needed. | -| [zig-http](./zig-http) | zig-0.11.0 | Basic example of a HTTP 1.1 server without any routing etc. | -| [zig-x11-box](./zig-x11-box) | zig-0.11.0 | Move a box around with arrow keys with Xlib and Zig. | -| [zig-kv-store](./zig-kv-store) | zig-0.11.0 | Simple Key-value store that mimics memcached written in Zig. | -| [zig-wad](./zig-wad) | zig-0.11.0 | Reads doom.wad and extracts the identification header. | -| [zig-os-props](./zig-os-props) | zig-0.11.0 | Detects properties of the target operating system. | +| Example | Compiler | What does it do? | +|----------------------------------------|------------|----------------------------------------------------------------| +| [c-asm](./c-asm) | clang-17 | Calls a function written in ASM from C code. | +| [c-embed](./c-embed) | clang-17 | Embedding external resources in compiled binary. | +| [c-signals](./c-signals) | clang-17 | Uses SIGUSR1 and SIGUSR2 as IPC mechanism. | +| [c-structs](./c-structs) | clang-17 | Saves and reads structs in/from binary files. | +| [zig-c-interop](./zig-c-interop) | zig-0.11.0 | Uses functions written in C from Zig code. | +| [zig-ppm](./zig-ppm) | zig-0.11.0 | Creates an image with random pixels in PPM image format. | +| [zig-structs](./zig-structs) | zig-0.11.0 | Serialization of a struct into JSON and then reading it back. | +| [zig-telnet](./zig-telnet) | zig-0.11.0 | Connects to Redis server like it is a basic telnet server. | +| [zig-x11](./zig-x11) | zig-0.11.0 | Uses X11 to create a basic window without any bindings needed. | +| [zig-http](./zig-http) | zig-0.11.0 | Basic example of a HTTP 1.1 server without any routing etc. | +| [zig-x11-box](./zig-x11-box) | zig-0.11.0 | Move a box around with arrow keys with Xlib and Zig. | +| [zig-kv-store](./zig-kv-store) | zig-0.11.0 | Simple Key-value store that mimics memcached written in Zig. | +| [zig-wad](./zig-wad) | zig-0.11.0 | Reads doom.wad and extracts the identification header. | +| [zig-os-props](./zig-os-props) | zig-0.11.0 | Detects properties of the target operating system. | +| [zig-tlv-encoding](./zig-tlv-encoding) | zig-0.13.0 | Naive implementation of TLV encoding in Zig. | ## License diff --git a/zig-tlv-encoding/Makefile b/zig-tlv-encoding/Makefile new file mode 100644 index 0000000..98beea6 --- /dev/null +++ b/zig-tlv-encoding/Makefile @@ -0,0 +1,2 @@ +default: + zig test main.zig diff --git a/zig-tlv-encoding/main.zig b/zig-tlv-encoding/main.zig new file mode 100644 index 0000000..d7e2809 --- /dev/null +++ b/zig-tlv-encoding/main.zig @@ -0,0 +1,97 @@ +// TLV format: https://devopedia.org/tlv-format +// Real world example: https://www.rfc-editor.org/rfc/rfc8609 +// Cool article: https://www.huy.rocks/everyday/12-11-2022-zig-using-zig-for-advent-of-code + +// Dummy TLV spec for encoding Linux devicei information +// +// Packet specification +// 1byte ... Tag +// 2bytes ... Length +// unknown ... Value +// +// Available tags: { 0x00 = vendor_name, 0x01 = model_name } +// Packet presented as a struct: Packet{ .vendor_name, .model_name } +// This assumes that the max value length can be 255. +// +// Test data from `lsusb` (`lscpu`): +// Bus 002 Device 003: ID 046d:086b Logitech, Inc. BRIO 4K Stream Edition +// Bus 001 Device 009: ID 3434:0350 Keychron Keychron V5 +// Bus 001 Device 006: ID 2433:b200 ASETEK [NZXT Kraken X60] +// Bus 001 Device 005: ID 046d:c548 Logitech, Inc. Logi Bolt Receiver + +const std = @import("std"); + +const TLVTag = enum(u8) { + VENDOR_NAME = 0x00, + MODEL_NAME = 0x01, +}; + +const TLVPacket = struct { + tag: TLVTag, + length: u8, + value: std.ArrayList(u8), + + pub fn printEncoded(self: *TLVPacket) void { + std.debug.print("\t", .{}); + std.debug.print("{X:0>2}-", .{@intFromEnum(self.tag)}); + std.debug.print("{X:0>2}-", .{self.length}); + + for (self.value.items) |val| { + std.debug.print("{X:0>2}", .{val}); + } + + std.debug.print("\n", .{}); + } +}; + +const TLVPayload = struct { + packets: std.ArrayList(TLVPacket), + allocator: std.mem.Allocator, + + pub fn init(allocator: std.mem.Allocator) TLVPayload { + return TLVPayload{ + .packets = std.ArrayList(TLVPacket).init(allocator), + .allocator = allocator, + }; + } + + pub fn deinit(self: *TLVPayload) void { + for (self.packets.items) |*packet| { + packet.value.deinit(); + } + self.packets.deinit(); + } + + pub fn append(self: *TLVPayload, tag: TLVTag, message: []const u8) !void { + var value = try std.ArrayList(u8).initCapacity(self.allocator, message.len); + try value.appendSlice(message); + + try self.packets.append(.{ + .tag = tag, + .length = @intCast(message.len), + .value = value, + }); + } +}; + +test "Create TLV payload manually" { + var gpa = std.heap.GeneralPurposeAllocator(.{}){}; + defer _ = gpa.deinit(); + + var payload = TLVPayload.init(gpa.allocator()); + defer payload.deinit(); + + try payload.append(.VENDOR_NAME, "Logitech, Inc."); + try payload.append(.MODEL_NAME, "BRIO 4K Stream Edition"); + + std.debug.print("Capacity: {d}\n", .{payload.packets.capacity}); + + for (payload.packets.items) |*packet| { + std.debug.print("Tag: {}, Length: {d}\n", .{ packet.tag, packet.length }); + packet.printEncoded(); + } +} + +pub fn main() void { + std.debug.print("Use `make test` or `zig test main.zig` instead.\n", .{}); +} |
