const std = @import("std");
pub const Tlv = struct {
tag: u8,
value: []const u8,
pub fn init(tag: u8, value: []const u8) Tlv {
return .{ .tag = tag, .value = value };
}
pub fn write(tlv: Tlv, writer: anytype) !void {
try writer.writeByte(tlv.tag);
try writer.writeByte(@intCast(tlv.value.len));
_ = try writer.write(tlv.value);
}
pub fn encode(tlvs: []const Tlv, allocator: std.mem.Allocator) ![]const u8 {
var buf = std.ArrayList(u8).init(allocator);
defer buf.deinit();
const writer = buf.writer();
for (tlvs) |tlv| {
try tlv.write(writer);
}
const E = std.base64.standard.Encoder;
const encoded = try allocator.alloc(u8, E.calcSize(buf.items.len));
_ = E.encode(encoded, buf.items);
return encoded;
}
pub fn decode(encoded: []const u8, allocator: std.mem.Allocator) !struct { tlvs: std.ArrayList(Tlv), decoded: []u8 } {
var E = std.base64.standard.Decoder;
const decodedLen = try E.calcSizeForSlice(encoded);
const decoded = try allocator.alloc(u8, decodedLen);
defer allocator.free(decoded);
try E.decode(decoded, encoded);
var tlvs = std.ArrayList(Tlv).init(allocator);
var i: usize = 0;
while (i < decoded.len-1) {
const len = decoded[i+1];
try tlvs.append(.{.tag = decoded[i], .value = decoded[i+2..][0..len] });
i += 2 + len;
}
return .{ .tlvs = tlvs, .decoded = decoded };
}
};
pub const Tlvs = struct {
items: []const Tlv,
pub fn tlvsToJson(self: Tlvs, allocator: std.mem.Allocator) ![]u8 {
var json = try allocator.alloc(u8, 2);
json[0] = '[';
json[1] = ']';
var i: usize = 0;
while (i < self.items.len) {
const tlv = self.items[i];
if (i == 0) {
json = try std.fmt.allocPrint(allocator, "{s}{{\"tag\": {d}, \"value\": \"{s}\"}}", .{json[0..json.len-1], tlv.tag, tlv.value});
} else {
json = try std.fmt.allocPrint(allocator, "{s},{{\"tag\": {d}, \"value\": \"{s}\"}}", .{json[0..json.len-1], tlv.tag, tlv.value});
}
i += 1;
}
json = try std.fmt.allocPrint(allocator, "{s}]", .{json});
return json;
}
};
pub fn main() !void {
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
const allocator = arena.allocator();
const tlvs = [_]Tlv{
Tlv.init(1, "Bonz carpet"),
Tlv.init(2, "310122393500003"),
Tlv.init(3, "2022-04-25T15:30:00Z"),
Tlv.init(4, "1200.00"),
Tlv.init(5, "180.00"),
};
const encoded = try Tlv.encode(&tlvs, allocator);
defer allocator.free(encoded);
std.debug.print("Base64: {s}\n", .{ encoded});
const result = try Tlv.decode(encoded, allocator);
for (result.tlvs.items) |tlv| {
std.debug.print("TLV.tagNum = {any}, TLV.tagName = {s}\n", .{tlv.tag, tlv.value});
}
std.debug.print("Decoded: {s}\n", .{std.mem.bytesAsSlice(u8, result.decoded)});
const tlvs2 = Tlvs{ .items = result.tlvs.items };
const json = try tlvs2.tlvsToJson(allocator);
std.debug.print("{s}\n", .{json});
allocator.free(json);
result.tlvs.deinit();
allocator.free(result.decoded);
}