Task: ASCII art diagram converter

C: #include <stdlib.h>
#include <stdio.h>
#include <string.h>
enum { MAX_ROWS=14, MAX_NAMES=20, NAME_SZ=80 };

char *Lines[MAX_ROWS] = {
   "  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+",
   "  |                      ID                       |",
   "  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+",
   "  |QR|   Opcode  |AA|TC|RD|RA|   Z    |   RCODE   |",
   "  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+",
   "  |                    QDCOUNT                    |",
   "  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+",
   "  |                    ANCOUNT                    |",
   "  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+",
   "  |                    NSCOUNT                    |",
   "  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+",
   "  |                    ARCOUNT                    |",
   "  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+"
};
typedef struct {
   unsigned bit3s;
   unsigned mask;
   unsigned data;
   char A[NAME_SZ+2];
}NAME_T;
NAME_T names[MAX_NAMES];
unsigned idx_name;
enum{ID,BITS,QDCOUNT,ANCOUNT,NSCOUNT,ARCOUNT,MAX_HDR};
unsigned header[MAX_HDR]; 
unsigned idx_hdr;

int  bit_hdr(char *pLine);
int  bit_names(char *pLine);
void dump_names(void);
void make_test_hdr(void);

int main(void){
   char *p1;   int rv;
   printf("Extract meta-data from bit-encoded text form\n");
   make_test_hdr();
   idx_name = 0;
   for( int i=0; i<MAX_ROWS;i++ ){
      p1 = Lines[i];
      if( p1==NULL ) break;
      if( rv = bit_hdr(Lines[i]), rv>0) continue;
      if( rv = bit_names(Lines[i]),rv>0) continue;
      
   }
   dump_names();
}

int  bit_hdr(char *pLine){ 
   char *p1 = strchr(pLine,'+');
   if( p1==NULL ) return 0;
   int numbits=0;
   for( int i=0; i<strlen(p1)-1; i+=3 ){
      if( p1[i] != '+' || p1[i+1] != '-' || p1[i+2] != '-' ) return 0;
      numbits++;
   }
   return numbits;
}

int  bit_names(char *pLine){ 
   char *p1,*p2 = pLine, tmp[80];
   unsigned sz=0, maskbitcount = 15;
   while(1){
      p1 = strchr(p2,'|');  if( p1==NULL ) break;
      p1++;
      p2 = strchr(p1,'|');  if( p2==NULL ) break;
      sz = p2-p1;
      tmp[sz] = 0;  
      int k=0;
      for(int j=0; j<sz;j++){  
	 if( p1[j] > ' ') tmp[k++] = p1[j];
      }
      tmp[k]= 0; sz++;
      NAME_T *pn = &names[idx_name++];
      strcpy(&pn->A[0], &tmp[0]);
      pn->bit3s = sz/3;
      if( pn->bit3s < 16 ){
	 for( int i=0; i<pn->bit3s; i++){
	    pn->mask |= 1 << maskbitcount--;
	 }
	 pn->data = header[idx_hdr] & pn->mask;
	 unsigned m2 = pn->mask;
	 while( (m2 & 1)==0 ){
	    m2>>=1; 
	    pn->data >>= 1;
	 }
	 if( pn->mask == 0xf ) idx_hdr++;

      }
      else{
	 pn->data = header[idx_hdr++];
      }
   }
   return sz;
}

void dump_names(void){ 
   NAME_T *pn;
   printf("-name-bits-mask-data-\n");
   for( int i=0; i<MAX_NAMES; i++ ){
      pn = &names[i];
      if( pn->bit3s < 1 ) break;
      printf("%10s %2d X%04x = %u\n",pn->A, pn->bit3s, pn->mask, pn->data);
   }
   puts("bye..");
}

void make_test_hdr(void){
   header[ID] = 1024;
   header[QDCOUNT] = 12;
   header[ANCOUNT] = 34;
   header[NSCOUNT] = 56;
   header[ARCOUNT] = 78;
   
   
   
   
   header[BITS] = 0xB50A;
}


C++: #include <array>
#include <bitset>
#include <iostream>

using namespace std;

struct FieldDetails {string_view Name; int NumBits;};



template <const char *T> consteval auto ParseDiagram()
{  
    
    constexpr string_view rawArt(T);
    constexpr auto firstBar = rawArt.find("|");
    constexpr auto lastBar = rawArt.find_last_of("|");
    constexpr auto art = rawArt.substr(firstBar, lastBar - firstBar);
    static_assert(firstBar < lastBar, "ASCII Table has no fields");
    
    
    constexpr auto numFields = 
        count(rawArt.begin(), rawArt.end(), '|') -
        count(rawArt.begin(), rawArt.end(), '\n') / 2;    
    array<FieldDetails, numFields> fields;
    
    
    bool isValidDiagram = true;
    int startDiagramIndex = 0;
    int totalBits = 0;
    for(int i = 0; i < numFields; )
    {
        auto beginningBar = art.find("|", startDiagramIndex);
        auto endingBar = art.find("|", beginningBar + 1);
        auto field = art.substr(beginningBar + 1, endingBar - beginningBar - 1);
        if(field.find("-") == field.npos) 
        {
            int numBits = (field.size() + 1) / 3;
            auto nameStart = field.find_first_not_of(" ");
            auto nameEnd = field.find_last_not_of(" ");
            if (nameStart > nameEnd || nameStart == string_view::npos) 
            {
                
                isValidDiagram = false;
                field = ""sv;
            }
            else
            {
                field = field.substr(nameStart, 1 + nameEnd - nameStart);
            }
            fields[i++] = FieldDetails {field, numBits};
            totalBits += numBits;
        }
        startDiagramIndex = endingBar;
    }
    
    int numRawBytes = isValidDiagram ? (totalBits - 1) / 8 + 1 : 0;
    return make_pair(fields, numRawBytes);
}


template <const char *T> auto Encode(auto inputValues)
{
    constexpr auto parsedDiagram = ParseDiagram<T>();
    static_assert(parsedDiagram.second > 0, "Invalid ASCII talble");
    array<unsigned char, parsedDiagram.second> data;

    int startBit = 0;
    int i = 0;
    for(auto value : inputValues)
    {
        const auto &field = parsedDiagram.first[i++];
        int remainingValueBits = field.NumBits;
        while(remainingValueBits > 0)
        {
            
            auto [fieldStartByte, fieldStartBit] = div(startBit, 8);
            int unusedBits = 8 - fieldStartBit;
            int numBitsToEncode = min({unusedBits, 8, field.NumBits});
            int divisor = 1 << (remainingValueBits - numBitsToEncode);
            unsigned char bitsToEncode = value / divisor;
            data[fieldStartByte] <<= numBitsToEncode;
            data[fieldStartByte] |= bitsToEncode;
            value %= divisor;
            startBit += numBitsToEncode;
            remainingValueBits -= numBitsToEncode;
        }
    }
    
    return data;
}


template <const char *T> void Decode(auto data)
{
    cout << "Name      Bit Pattern\n";
    cout << "=======   ================\n";
    constexpr auto parsedDiagram = ParseDiagram<T>();
    static_assert(parsedDiagram.second > 0, "Invalid ASCII talble");

    int startBit = 0;
    for(const auto& field : parsedDiagram.first)
    {
        
        auto [fieldStartByte, fieldStartBit] = div(startBit, 8);
        unsigned char firstByte = data[fieldStartByte];
        firstByte <<= fieldStartBit;
        firstByte >>= fieldStartBit;
        int64_t value = firstByte;
        auto endBit = startBit + field.NumBits;
        auto [fieldEndByte, fieldEndBit] = div(endBit, 8);
        fieldEndByte = min(fieldEndByte, (int)(ssize(data) - 1));
        for(int index = fieldStartByte + 1; index <= fieldEndByte; index++)
        {
            value <<= 8;
            value += data[index];
        }
        value >>= fieldEndBit;
        startBit = endBit;
        
        cout << field.Name << 
            string_view("        ", (7 - field.Name.size())) << "   " << 
            string_view(bitset<64>(value).to_string()).substr(64 - field.NumBits, 64) <<  "\n";
    }
            
}

int main(void) 
{
    static constexpr char art[] = R"(
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    |                      ID                       |
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    |QR|   Opcode  |AA|TC|RD|RA|   Z    |   RCODE   |
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    |                    QDCOUNT                    |
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    |                    ANCOUNT                    |
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    |                    NSCOUNT                    |
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    |                    ARCOUNT                    |
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+)";
    
    
    auto rawData = Encode<art> (initializer_list<int64_t> {
        30791,
        0, 15, 0, 1, 1, 1, 3, 15,
        21654,
        57646,
        7153,
        27044
    });
    
    cout << "Raw encoded data in hex:\n";
    for (auto v : rawData) printf("%.2X", v);
    cout << "\n\n";
    
    cout << "Decoded raw data:\n";
    Decode<art>(rawData);
}