|
diff --git a/README.md b/README.md
|
| ... |
| 16 |
> also written in the most explicit way and lacks massively when it |
16 |
> also written in the most explicit way and lacks massively when it |
| 17 |
> comes to checking of errors etc. |
17 |
> comes to checking of errors etc. |
| 18 |
|
18 |
|
| 19 |
| Example | Compiler | What does it do? | |
19 |
| Example | Compiler | What does it do? | |
| 20 |
|----------------------------------|------------|----------------------------------------------------------------| |
20 |
|----------------------------------------|------------|----------------------------------------------------------------| |
| 21 |
| [c-asm](./c-asm) | clang-17 | Calls a function written in ASM from C code. | |
21 |
| [c-asm](./c-asm) | clang-17 | Calls a function written in ASM from C code. | |
| 22 |
| [c-embed](./c-embed) | clang-17 | Embedding external resources in compiled binary. | |
22 |
| [c-embed](./c-embed) | clang-17 | Embedding external resources in compiled binary. | |
| 23 |
| [c-signals](./c-signals) | clang-17 | Uses SIGUSR1 and SIGUSR2 as IPC mechanism. | |
23 |
| [c-signals](./c-signals) | clang-17 | Uses SIGUSR1 and SIGUSR2 as IPC mechanism. | |
| 24 |
| [c-structs](./c-structs) | clang-17 | Saves and reads structs in/from binary files. | |
24 |
| [c-structs](./c-structs) | clang-17 | Saves and reads structs in/from binary files. | |
| 25 |
| [zig-c-interop](./zig-c-interop) | zig-0.11.0 | Uses functions written in C from Zig code. | |
25 |
| [zig-c-interop](./zig-c-interop) | zig-0.11.0 | Uses functions written in C from Zig code. | |
| 26 |
| [zig-ppm](./zig-ppm) | zig-0.11.0 | Creates an image with random pixels in PPM image format. | |
26 |
| [zig-ppm](./zig-ppm) | zig-0.11.0 | Creates an image with random pixels in PPM image format. | |
| 27 |
| [zig-structs](./zig-structs) | zig-0.11.0 | Serialization of a struct into JSON and then reading it back. | |
27 |
| [zig-structs](./zig-structs) | zig-0.11.0 | Serialization of a struct into JSON and then reading it back. | |
| 28 |
| [zig-telnet](./zig-telnet) | zig-0.11.0 | Connects to Redis server like it is a basic telnet server. | |
28 |
| [zig-telnet](./zig-telnet) | zig-0.11.0 | Connects to Redis server like it is a basic telnet server. | |
| 29 |
| [zig-x11](./zig-x11) | zig-0.11.0 | Uses X11 to create a basic window without any bindings needed. | |
29 |
| [zig-x11](./zig-x11) | zig-0.11.0 | Uses X11 to create a basic window without any bindings needed. | |
| 30 |
| [zig-http](./zig-http) | zig-0.11.0 | Basic example of a HTTP 1.1 server without any routing etc. | |
30 |
| [zig-http](./zig-http) | zig-0.11.0 | Basic example of a HTTP 1.1 server without any routing etc. | |
| 31 |
| [zig-x11-box](./zig-x11-box) | zig-0.11.0 | Move a box around with arrow keys with Xlib and Zig. | |
31 |
| [zig-x11-box](./zig-x11-box) | zig-0.11.0 | Move a box around with arrow keys with Xlib and Zig. | |
| 32 |
| [zig-kv-store](./zig-kv-store) | zig-0.11.0 | Simple Key-value store that mimics memcached written in Zig. | |
32 |
| [zig-kv-store](./zig-kv-store) | zig-0.11.0 | Simple Key-value store that mimics memcached written in Zig. | |
| 33 |
| [zig-wad](./zig-wad) | zig-0.11.0 | Reads doom.wad and extracts the identification header. | |
33 |
| [zig-wad](./zig-wad) | zig-0.11.0 | Reads doom.wad and extracts the identification header. | |
| 34 |
| [zig-os-props](./zig-os-props) | zig-0.11.0 | Detects properties of the target operating system. | |
34 |
| [zig-os-props](./zig-os-props) | zig-0.11.0 | Detects properties of the target operating system. | |
|
|
35 |
| [zig-tlv-encoding](./zig-tlv-encoding) | zig-0.13.0 | Naive implementation of TLV encoding in Zig. | |
| 35 |
|
36 |
|
| 36 |
## License |
37 |
## License |
| 37 |
|
38 |
|
| ... |
|
diff --git a/zig-tlv-encoding/main.zig b/zig-tlv-encoding/main.zig
|
|
|
1 |
// TLV format: https://devopedia.org/tlv-format |
|
|
2 |
// Real world example: https://www.rfc-editor.org/rfc/rfc8609 |
|
|
3 |
// Cool article: https://www.huy.rocks/everyday/12-11-2022-zig-using-zig-for-advent-of-code |
|
|
4 |
|
|
|
5 |
// Dummy TLV spec for encoding Linux devicei information |
|
|
6 |
// |
|
|
7 |
// Packet specification |
|
|
8 |
// 1byte ... Tag |
|
|
9 |
// 2bytes ... Length |
|
|
10 |
// unknown ... Value |
|
|
11 |
// |
|
|
12 |
// Available tags: { 0x00 = vendor_name, 0x01 = model_name } |
|
|
13 |
// Packet presented as a struct: Packet{ .vendor_name, .model_name } |
|
|
14 |
// This assumes that the max value length can be 255. |
|
|
15 |
// |
|
|
16 |
// Test data from `lsusb` (`lscpu`): |
|
|
17 |
// Bus 002 Device 003: ID 046d:086b Logitech, Inc. BRIO 4K Stream Edition |
|
|
18 |
// Bus 001 Device 009: ID 3434:0350 Keychron Keychron V5 |
|
|
19 |
// Bus 001 Device 006: ID 2433:b200 ASETEK [NZXT Kraken X60] |
|
|
20 |
// Bus 001 Device 005: ID 046d:c548 Logitech, Inc. Logi Bolt Receiver |
|
|
21 |
|
|
|
22 |
const std = @import("std"); |
|
|
23 |
|
|
|
24 |
const TLVTag = enum(u8) { |
|
|
25 |
VENDOR_NAME = 0x00, |
|
|
26 |
MODEL_NAME = 0x01, |
|
|
27 |
}; |
|
|
28 |
|
|
|
29 |
const TLVPacket = struct { |
|
|
30 |
tag: TLVTag, |
|
|
31 |
length: u8, |
|
|
32 |
value: std.ArrayList(u8), |
|
|
33 |
|
|
|
34 |
pub fn printEncoded(self: *TLVPacket) void { |
|
|
35 |
std.debug.print("\t", .{}); |
|
|
36 |
std.debug.print("{X:0>2}-", .{@intFromEnum(self.tag)}); |
|
|
37 |
std.debug.print("{X:0>2}-", .{self.length}); |
|
|
38 |
|
|
|
39 |
for (self.value.items) |val| { |
|
|
40 |
std.debug.print("{X:0>2}", .{val}); |
|
|
41 |
} |
|
|
42 |
|
|
|
43 |
std.debug.print("\n", .{}); |
|
|
44 |
} |
|
|
45 |
}; |
|
|
46 |
|
|
|
47 |
const TLVPayload = struct { |
|
|
48 |
packets: std.ArrayList(TLVPacket), |
|
|
49 |
allocator: std.mem.Allocator, |
|
|
50 |
|
|
|
51 |
pub fn init(allocator: std.mem.Allocator) TLVPayload { |
|
|
52 |
return TLVPayload{ |
|
|
53 |
.packets = std.ArrayList(TLVPacket).init(allocator), |
|
|
54 |
.allocator = allocator, |
|
|
55 |
}; |
|
|
56 |
} |
|
|
57 |
|
|
|
58 |
pub fn deinit(self: *TLVPayload) void { |
|
|
59 |
for (self.packets.items) |*packet| { |
|
|
60 |
packet.value.deinit(); |
|
|
61 |
} |
|
|
62 |
self.packets.deinit(); |
|
|
63 |
} |
|
|
64 |
|
|
|
65 |
pub fn append(self: *TLVPayload, tag: TLVTag, message: []const u8) !void { |
|
|
66 |
var value = try std.ArrayList(u8).initCapacity(self.allocator, message.len); |
|
|
67 |
try value.appendSlice(message); |
|
|
68 |
|
|
|
69 |
try self.packets.append(.{ |
|
|
70 |
.tag = tag, |
|
|
71 |
.length = @intCast(message.len), |
|
|
72 |
.value = value, |
|
|
73 |
}); |
|
|
74 |
} |
|
|
75 |
}; |
|
|
76 |
|
|
|
77 |
test "Create TLV payload manually" { |
|
|
78 |
var gpa = std.heap.GeneralPurposeAllocator(.{}){}; |
|
|
79 |
defer _ = gpa.deinit(); |
|
|
80 |
|
|
|
81 |
var payload = TLVPayload.init(gpa.allocator()); |
|
|
82 |
defer payload.deinit(); |
|
|
83 |
|
|
|
84 |
try payload.append(.VENDOR_NAME, "Logitech, Inc."); |
|
|
85 |
try payload.append(.MODEL_NAME, "BRIO 4K Stream Edition"); |
|
|
86 |
|
|
|
87 |
std.debug.print("Capacity: {d}\n", .{payload.packets.capacity}); |
|
|
88 |
|
|
|
89 |
for (payload.packets.items) |*packet| { |
|
|
90 |
std.debug.print("Tag: {}, Length: {d}\n", .{ packet.tag, packet.length }); |
|
|
91 |
packet.printEncoded(); |
|
|
92 |
} |
|
|
93 |
} |
|
|
94 |
|
|
|
95 |
pub fn main() void { |
|
|
96 |
std.debug.print("Use `make test` or `zig test main.zig` instead.\n", .{}); |
|
|
97 |
} |