Search code examples
zig

How do I escape Nonprintable Characters


I have the below code:

const std = @import("std");

fn getTLVForValue(writer: anytype, tagNum: []const u8, tagValue: []const u8) !void {
    _ = try writer.write(tagNum);;
    _ = try writer.writeByte(@intCast(tagValue.len));
    _ = try writer.write(tagValue);
}

pub fn main() !void {
    var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
    const allocator = arena.allocator();
    var qrCodeBuf = std.ArrayList(u8).init(allocator);
    defer qrCodeBuf.deinit();
    const writer = qrCodeBuf.writer();

    //1. Seller Name
    try getTLVForValue(writer, "01", "Bobs Basement Records");

    //2. VAT Registration
    try getTLVForValue(writer, "02", "312345678901233");

    //3. Time stamp
    try getTLVForValue(writer, "03", "12-12-2023");

    //4. tax Total
    try getTLVForValue(writer, "04", "1000");

    //5. Vat Total
    try getTLVForValue(writer, "05", "115");

    //6. Hashed XML
    try getTLVForValue(writer, "06", "dsds");

    //7. key
    try getTLVForValue(writer, "07", "125");

    //8. Signature
    try getTLVForValue(writer, "08", "dsfsd");

    std.debug.print("{any}\n", .{qrCodeBuf.items});

    std.debug.print("Hex string: {s}\n", .{std.fmt.fmtSliceHexUpper(qrCodeBuf.items)});
    // const hex = try std.fmt.allocPrint("{s}", .{std.fmt.fmtSliceHexUpper(qrCodeBuf.items)});

    const output_buffer = try allocator.alloc(u8, std.base64.standard.Encoder.calcSize(qrCodeBuf.items.len));
    defer allocator.free(output_buffer);
    const data = std.base64.standard.Encoder.encode(output_buffer, qrCodeBuf.items);
    std.debug.print("{s}\n", .{data});

    const decode_buf = try allocator.alloc(u8, try std.base64.standard.Decoder.calcSizeForSlice(data));
    try std.base64.standard.Decoder.decode(decode_buf, data);
    std.debug.print("{s}\n", .{decode_buf});
    std.debug.print("{}\n", .{std.zig.fmtEscapes(decode_buf)});

    try std.testing.expectEqualStrings(qrCodeBuf.items, decode_buf);
}

And it is giving me the final output as:

01\x15Bobs Basement Records02\x0f31234567890123303\n12-12-202304\x04100005\x0311506\x04dsds07\x0312508\x05dsfsd

But here I'm getting a noneprintable ASCII characters instead of the numbers, I get for example \n instead of 10 and \x15 instead of 21 and so on as per the mapping showing here.

I'm opened for any alternate option to get the function getTLVForValue return the TLV - Tag - Length - Value, so that I get for example 0103xxxx for a tag the is of the length 3 and having the tagNum as 01.

I'm trying to write a code that is doing what is explained in the screen shoot below:

image


Solution

  • You're writing values as bytes instead of formatting them as numbers:

    try writer.writeByte(@intCast(tagValue.len));
    

    Do this:

    try writer.print("{}", .{ tagValue.len });