Task 131: .DBC File Format

Task 131: .DBC File Format

The .DBC file format, as specified in documentation from Vector Informatik GmbH and related technical resources, is a standardized text-based format primarily used in automotive Controller Area Network (CAN) systems to define network communications, including messages, signals, and associated attributes for decoding raw CAN bus data into interpretable physical values.

The properties intrinsic to the .DBC file format include the following structural elements, which define its syntax and content organization:

  • VERSION: A string indicating the file version for compatibility (e.g., VERSION "RELEASE_1_2").
  • NS_: Namespace section listing supported symbols or features (e.g., NS_ : NS_DESC_ CM_ BA_DEF_).
  • BS_: Bus configuration, specifying speed and bit timing (e.g., BS_: 500000 : 0,0).
  • BU_: List of network nodes or Electronic Control Units (ECUs) (e.g., BU_: ECU1 ECU2).
  • BO_: Message definitions, including CAN ID (decimal), name, data length (DLC in bytes), and transmitter node (e.g., BO_ 123 MessageName: 8 Transmitter).
  • SG_: Signal definitions within messages, including name, optional multiplexer (M or m with identifier), start bit, bit length, byte order (@0 for big-endian/Motorola, @1 for little-endian/Intel), signedness (+ for unsigned, - for signed), scaling factor and offset, minimum and maximum values, unit, and optional receivers (e.g., SG_ SignalName : 0|8@1+ (1,0) [0|255] "unit" Receiver).
  • CM_: Comments for annotations on messages, signals, or nodes (e.g., CM_ BO_ 123 "Comment text";).
  • BA_DEF_: Attribute definitions for custom properties on messages, signals, or nodes, including type (e.g., INT, ENUM) (e.g., BA_DEF_ BO_ "AttributeName" INT 0 100;).
  • BA_DEF_DEF_: Default values for attributes (e.g., BA_DEF_DEF_ "AttributeName" 0;).
  • BA_: Assigned attribute values (e.g., BA_ "AttributeName" BO_ 123 1;).
  • VAL_: Value tables for enumerated signal interpretations (e.g., VAL_ 123 SignalName 0 "Off" 1 "On";).
  • SIG_VALTYPE_: Signal value types for advanced data representation (e.g., float or double) (e.g., SIG_VALTYPE_ 123 SignalName 1; for single precision float).
  • BO_TX_BU_: Message transmission associations with nodes (e.g., BO_TX_BU_ 123 : ECU1,ECU2;).
  • Relation Attributes: Additional relational definitions such as BA_DEF_REL_, BA_REL_, BU_SG_REL_ for linking elements.

These properties collectively enable the format's role in CAN data description, with text-based syntax allowing editing via standard tools.

Two direct download links for .DBC files are:

The following is an embedded HTML/JavaScript code snippet suitable for a static page (e.g., in a Ghost blog or similar). It enables drag-and-drop of a .DBC file, parses its content to extract the listed properties, and displays them on the screen. The parser handles basic line-by-line extraction assuming standard DBC syntax; error handling is minimal for brevity.

DBC File Parser
Drag and drop a .DBC file here
  1. The following Python class handles opening, decoding (parsing), reading, writing, and printing of .DBC file properties. It assumes read/write operations on text files and includes basic parsing logic.
import os

class DBCHandler:
    def __init__(self, filepath=None):
        self.filepath = filepath
        self.properties = {
            'VERSION': '', 'NS_': [], 'BS_': '', 'BU_': [], 'BO_': [], 'SG_': [], 'CM_': [], 
            'BA_DEF_': [], 'BA_DEF_DEF_': [], 'BA_': [], 'VAL_': [], 'SIG_VALTYPE_': [], 
            'BO_TX_BU_': [], 'Relations': []
        }
        if filepath:
            self.read_and_decode()

    def read_and_decode(self):
        if not os.path.exists(self.filepath):
            raise FileNotFoundError(f"File {self.filepath} not found.")
        with open(self.filepath, 'r') as f:
            content = f.read()
        lines = [line.strip() for line in content.split('\n') if line.strip()]
        current_bo = None
        i = 0
        while i < len(lines):
            line = lines[i]
            if line.startswith('VERSION'):
                self.properties['VERSION'] = line.replace('VERSION', '').strip().replace('"', '')
            elif line.startswith('NS_ :'):
                i += 1
                while i < len(lines) and not lines[i].startswith('BS_'):
                    if lines[i].strip():
                        self.properties['NS_'].append(lines[i].strip())
                    i += 1
                i -= 1  # Adjust for loop increment
            elif line.startswith('BS_:'):
                self.properties['BS_'] = line.replace('BS_:', '').strip()
            elif line.startswith('BU_:'):
                self.properties['BU_'] = line.replace('BU_:', '').strip().split()
            elif line.startswith('BO_'):
                current_bo = line
                self.properties['BO_'].append(line)
            elif line.startswith('SG_') and current_bo:
                self.properties['SG_'].append({'message': current_bo, 'signal': line})
            elif line.startswith('CM_'):
                self.properties['CM_'].append(line)
            elif line.startswith('BA_DEF_'):
                self.properties['BA_DEF_'].append(line)
            elif line.startswith('BA_DEF_DEF_'):
                self.properties['BA_DEF_DEF_'].append(line)
            elif line.startswith('BA_'):
                self.properties['BA_'].append(line)
            elif line.startswith('VAL_'):
                self.properties['VAL_'].append(line)
            elif line.startswith('SIG_VALTYPE_'):
                self.properties['SIG_VALTYPE_'].append(line)
            elif line.startswith('BO_TX_BU_'):
                self.properties['BO_TX_BU_'].append(line)
            elif line.startswith(('BA_DEF_REL_', 'BA_REL_', 'BU_SG_REL_')):
                self.properties['Relations'].append(line)
            i += 1

    def print_properties(self):
        for key, value in self.properties.items():
            print(f"{key}:")
            if isinstance(value, list):
                for item in value:
                    if isinstance(item, dict):
                        print(f"- Message: {item['message']}")
                        print(f"  Signal: {item['signal']}")
                    else:
                        print(f"- {item}")
            else:
                print(value)
            print()

    def write(self, new_filepath=None):
        if not new_filepath:
            new_filepath = self.filepath or 'output.dbc'
        with open(new_filepath, 'w') as f:
            # Reconstruct file from properties (simplified; full reconstruction may require more logic)
            if self.properties['VERSION']:
                f.write(f'VERSION "{self.properties["VERSION"]}"\n\n')
            if self.properties['NS_']:
                f.write('NS_ :\n')
                for ns in self.properties['NS_']:
                    f.write(f'  {ns}\n')
            if self.properties['BS_']:
                f.write(f'\nBS_: {self.properties["BS_"]}\n')
            if self.properties['BU_']:
                f.write(f'\nBU_: {" ".join(self.properties["BU_"])}\n')
            for bo in self.properties['BO_']:
                f.write(f'\n{bo}\n')
                for sg in [s for s in self.properties['SG_'] if s['message'] == bo]:
                    f.write(f' {sg["signal"]}\n')
            for cm in self.properties['CM_']:
                f.write(f'\n{cm}\n')
            for ba_def in self.properties['BA_DEF_']:
                f.write(f'{ba_def}\n')
            for ba_def_def in self.properties['BA_DEF_DEF_']:
                f.write(f'{ba_def_def}\n')
            for ba in self.properties['BA_']:
                f.write(f'{ba}\n')
            for val in self.properties['VAL_']:
                f.write(f'{val}\n')
            for sig_val in self.properties['SIG_VALTYPE_']:
                f.write(f'{sig_val}\n')
            for bo_tx in self.properties['BO_TX_BU_']:
                f.write(f'{bo_tx}\n')
            for rel in self.properties['Relations']:
                f.write(f'{rel}\n')

# Example usage:
# handler = DBCHandler('path/to/file.dbc')
# handler.print_properties()
# handler.write('path/to/new.dbc')
  1. The following Java class provides equivalent functionality for handling .DBC files.
import java.io.*;
import java.util.*;

public class DBCHandler {
    private String filepath;
    private Map<String, Object> properties = new HashMap<>();

    public DBCHandler(String filepath) {
        this.filepath = filepath;
        properties.put("VERSION", "");
        properties.put("NS_", new ArrayList<String>());
        properties.put("BS_", "");
        properties.put("BU_", new ArrayList<String>());
        properties.put("BO_", new ArrayList<String>());
        properties.put("SG_", new ArrayList<Map<String, String>>());
        properties.put("CM_", new ArrayList<String>());
        properties.put("BA_DEF_", new ArrayList<String>());
        properties.put("BA_DEF_DEF_", new ArrayList<String>());
        properties.put("BA_", new ArrayList<String>());
        properties.put("VAL_", new ArrayList<String>());
        properties.put("SIG_VALTYPE_", new ArrayList<String>());
        properties.put("BO_TX_BU_", new ArrayList<String>());
        properties.put("Relations", new ArrayList<String>());
        if (filepath != null) {
            readAndDecode();
        }
    }

    public void readAndDecode() {
        File file = new File(filepath);
        if (!file.exists()) {
            throw new RuntimeException("File " + filepath + " not found.");
        }
        try (BufferedReader reader = new BufferedReader(new FileReader(file))) {
            String line;
            String currentBO = null;
            boolean inNS = false;
            while ((line = reader.readLine()) != null) {
                line = line.trim();
                if (line.isEmpty()) continue;
                if (line.startsWith("VERSION")) {
                    properties.put("VERSION", line.replace("VERSION", "").trim().replace("\"", ""));
                } else if (line.startsWith("NS_ :")) {
                    inNS = true;
                } else if (inNS && line.startsWith("BS_")) {
                    inNS = false;
                    properties.put("BS_", line.replace("BS_:", "").trim());
                } else if (inNS) {
                    ((List<String>) properties.get("NS_")).add(line);
                } else if (line.startsWith("BS_:")) {
                    properties.put("BS_", line.replace("BS_:", "").trim());
                } else if (line.startsWith("BU_:")) {
                    String[] nodes = line.replace("BU_:", "").trim().split("\\s+");
                    properties.put("BU_", Arrays.asList(nodes));
                } else if (line.startsWith("BO_")) {
                    currentBO = line;
                    ((List<String>) properties.get("BO_")).add(line);
                } else if (line.startsWith("SG_") && currentBO != null) {
                    Map<String, String> sgMap = new HashMap<>();
                    sgMap.put("message", currentBO);
                    sgMap.put("signal", line);
                    ((List<Map<String, String>>) properties.get("SG_")).add(sgMap);
                } else if (line.startsWith("CM_")) {
                    ((List<String>) properties.get("CM_")).add(line);
                } else if (line.startsWith("BA_DEF_")) {
                    ((List<String>) properties.get("BA_DEF_")).add(line);
                } else if (line.startsWith("BA_DEF_DEF_")) {
                    ((List<String>) properties.get("BA_DEF_DEF_")).add(line);
                } else if (line.startsWith("BA_")) {
                    ((List<String>) properties.get("BA_")).add(line);
                } else if (line.startsWith("VAL_")) {
                    ((List<String>) properties.get("VAL_")).add(line);
                } else if (line.startsWith("SIG_VALTYPE_")) {
                    ((List<String>) properties.get("SIG_VALTYPE_")).add(line);
                } else if (line.startsWith("BO_TX_BU_")) {
                    ((List<String>) properties.get("BO_TX_BU_")).add(line);
                } else if (line.startsWith("BA_DEF_REL_") || line.startsWith("BA_REL_") || line.startsWith("BU_SG_REL_")) {
                    ((List<String>) properties.get("Relations")).add(line);
                }
            }
        } catch (IOException e) {
            throw new RuntimeException("Error reading file: " + e.getMessage());
        }
    }

    public void printProperties() {
        for (Map.Entry<String, Object> entry : properties.entrySet()) {
            System.out.println(entry.getKey() + ":");
            if (entry.getValue() instanceof List) {
                List<?> list = (List<?>) entry.getValue();
                for (Object item : list) {
                    if (item instanceof Map) {
                        Map<?, ?> map = (Map<?, ?>) item;
                        System.out.println("- Message: " + map.get("message"));
                        System.out.println("  Signal: " + map.get("signal"));
                    } else {
                        System.out.println("- " + item);
                    }
                }
            } else {
                System.out.println(entry.getValue());
            }
            System.out.println();
        }
    }

    public void write(String newFilepath) {
        if (newFilepath == null) {
            newFilepath = filepath != null ? filepath : "output.dbc";
        }
        try (BufferedWriter writer = new BufferedWriter(new FileWriter(newFilepath))) {
            if (!((String) properties.get("VERSION")).isEmpty()) {
                writer.write("VERSION \"" + properties.get("VERSION") + "\"\n\n");
            }
            List<String> nsList = (List<String>) properties.get("NS_");
            if (!nsList.isEmpty()) {
                writer.write("NS_ :\n");
                for (String ns : nsList) {
                    writer.write("  " + ns + "\n");
                }
            }
            if (!((String) properties.get("BS_")).isEmpty()) {
                writer.write("\nBS_: " + properties.get("BS_") + "\n");
            }
            List<String> buList = (List<String>) properties.get("BU_");
            if (!buList.isEmpty()) {
                writer.write("\nBU_: " + String.join(" ", buList) + "\n");
            }
            List<String> boList = (List<String>) properties.get("BO_");
            List<Map<String, String>> sgList = (List<Map<String, String>>) properties.get("SG_");
            for (String bo : boList) {
                writer.write("\n" + bo + "\n");
                for (Map<String, String> sg : sgList) {
                    if (sg.get("message").equals(bo)) {
                        writer.write(" " + sg.get("signal") + "\n");
                    }
                }
            }
            for (String cm : (List<String>) properties.get("CM_")) {
                writer.write("\n" + cm + "\n");
            }
            for (String baDef : (List<String>) properties.get("BA_DEF_")) {
                writer.write(baDef + "\n");
            }
            for (String baDefDef : (List<String>) properties.get("BA_DEF_DEF_")) {
                writer.write(baDefDef + "\n");
            }
            for (String ba : (List<String>) properties.get("BA_")) {
                writer.write(ba + "\n");
            }
            for (String val : (List<String>) properties.get("VAL_")) {
                writer.write(val + "\n");
            }
            for (String sigVal : (List<String>) properties.get("SIG_VALTYPE_")) {
                writer.write(sigVal + "\n");
            }
            for (String boTx : (List<String>) properties.get("BO_TX_BU_")) {
                writer.write(boTx + "\n");
            }
            for (String rel : (List<String>) properties.get("Relations")) {
                writer.write(rel + "\n");
            }
        } catch (IOException e) {
            throw new RuntimeException("Error writing file: " + e.getMessage());
        }
    }

    // Example usage:
    // public static void main(String[] args) {
    //     DBCHandler handler = new DBCHandler("path/to/file.dbc");
    //     handler.printProperties();
    //     handler.write("path/to/new.dbc");
    // }
}
  1. The following JavaScript class (Node.js compatible) handles .DBC files similarly. It requires the 'fs' module for file operations.
const fs = require('fs');

class DBCHandler {
    constructor(filepath = null) {
        this.filepath = filepath;
        this.properties = {
            VERSION: '',
            NS_: [],
            BS_: '',
            BU_: [],
            BO_: [],
            SG_: [],
            CM_: [],
            BA_DEF_: [],
            BA_DEF_DEF_: [],
            BA_: [],
            VAL_: [],
            SIG_VALTYPE_: [],
            BO_TX_BU_: [],
            Relations: []
        };
        if (filepath) {
            this.readAndDecode();
        }
    }

    readAndDecode() {
        if (!fs.existsSync(this.filepath)) {
            throw new Error(`File ${this.filepath} not found.`);
        }
        const content = fs.readFileSync(this.filepath, 'utf8');
        const lines = content.split('\n').map(line => line.trim()).filter(line => line);
        let currentBO = null;
        let i = 0;
        while (i < lines.length) {
            const line = lines[i];
            if (line.startsWith('VERSION')) {
                this.properties.VERSION = line.replace('VERSION', '').trim().replace(/["']/g, '');
            } else if (line.startsWith('NS_ :')) {
                i++;
                while (i < lines.length && !lines[i].startsWith('BS_')) {
                    if (lines[i].trim()) this.properties.NS_.push(lines[i].trim());
                    i++;
                }
                i--;  // Adjust for loop
            } else if (line.startsWith('BS_:')) {
                this.properties.BS_ = line.replace('BS_:', '').trim();
            } else if (line.startsWith('BU_:')) {
                this.properties.BU_ = line.replace('BU_:', '').trim().split(/\s+/);
            } else if (line.startsWith('BO_')) {
                currentBO = line;
                this.properties.BO_.push(line);
            } else if (line.startsWith('SG_') && currentBO) {
                this.properties.SG_.push({ message: currentBO, signal: line });
            } else if (line.startsWith('CM_')) {
                this.properties.CM_.push(line);
            } else if (line.startsWith('BA_DEF_')) {
                this.properties.BA_DEF_.push(line);
            } else if (line.startsWith('BA_DEF_DEF_')) {
                this.properties.BA_DEF_DEF_.push(line);
            } else if (line.startsWith('BA_')) {
                this.properties.BA_.push(line);
            } else if (line.startsWith('VAL_')) {
                this.properties.VAL_.push(line);
            } else if (line.startsWith('SIG_VALTYPE_')) {
                this.properties.SIG_VALTYPE_.push(line);
            } else if (line.startsWith('BO_TX_BU_')) {
                this.properties.BO_TX_BU_.push(line);
            } else if (line.startsWith('BA_DEF_REL_') || line.startsWith('BA_REL_') || line.startsWith('BU_SG_REL_')) {
                this.properties.Relations.push(line);
            }
            i++;
        }
    }

    printProperties() {
        for (const [key, value] of Object.entries(this.properties)) {
            console.log(`${key}:`);
            if (Array.isArray(value)) {
                value.forEach(item => {
                    if (typeof item === 'object') {
                        console.log(`- Message: ${item.message}`);
                        console.log(`  Signal: ${item.signal}`);
                    } else {
                        console.log(`- ${item}`);
                    }
                });
            } else {
                console.log(value);
            }
            console.log('');
        }
    }

    write(newFilepath = null) {
        if (!newFilepath) newFilepath = this.filepath || 'output.dbc';
        let output = '';
        if (this.properties.VERSION) output += `VERSION "${this.properties.VERSION}"\n\n`;
        if (this.properties.NS_.length) {
            output += 'NS_ :\n';
            this.properties.NS_.forEach(ns => output += `  ${ns}\n`);
        }
        if (this.properties.BS_) output += `\nBS_: ${this.properties.BS_}\n`;
        if (this.properties.BU_.length) output += `\nBU_: ${this.properties.BU_.join(' ')}\n`;
        this.properties.BO_.forEach(bo => {
            output += `\n${bo}\n`;
            this.properties.SG_.filter(sg => sg.message === bo).forEach(sg => output += ` ${sg.signal}\n`);
        });
        this.properties.CM_.forEach(cm => output += `\n${cm}\n`);
        this.properties.BA_DEF_.forEach(baDef => output += `${baDef}\n`);
        this.properties.BA_DEF_DEF_.forEach(baDefDef => output += `${baDefDef}\n`);
        this.properties.BA_.forEach(ba => output += `${ba}\n`);
        this.properties.VAL_.forEach(val => output += `${val}\n`);
        this.properties.SIG_VALTYPE_.forEach(sigVal => output += `${sigVal}\n`);
        this.properties.BO_TX_BU_.forEach(boTx => output += `${boTx}\n`);
        this.properties.Relations.forEach(rel => output += `${rel}\n`);
        fs.writeFileSync(newFilepath, output);
    }
}

// Example usage:
// const handler = new DBCHandler('path/to/file.dbc');
// handler.printProperties();
// handler.write('path/to/new.dbc');
  1. The following C++ class provides equivalent functionality. It uses standard library components for file handling.
#include <iostream>
#include <fstream>
#include <sstream>
#include <vector>
#include <map>
#include <string>

class DBCHandler {
private:
    std::string filepath;
    std::map<std::string, std::string> simpleProps;
    std::map<std::string, std::vector<std::string>> listProps;
    std::vector<std::map<std::string, std::string>> sgProps;  // For SG_ with message-signal pairs

public:
    DBCHandler(const std::string& fp = "") : filepath(fp) {
        simpleProps["VERSION"] = "";
        simpleProps["BS_"] = "";
        listProps["NS_"] = {};
        listProps["BU_"] = {};
        listProps["BO_"] = {};
        listProps["CM_"] = {};
        listProps["BA_DEF_"] = {};
        listProps["BA_DEF_DEF_"] = {};
        listProps["BA_"] = {};
        listProps["VAL_"] = {};
        listProps["SIG_VALTYPE_"] = {};
        listProps["BO_TX_BU_"] = {};
        listProps["Relations"] = {};
        if (!filepath.empty()) {
            readAndDecode();
        }
    }

    void readAndDecode() {
        std::ifstream file(filepath);
        if (!file.is_open()) {
            throw std::runtime_error("File " + filepath + " not found.");
        }
        std::string line, currentBO;
        bool inNS = false;
        while (std::getline(file, line)) {
            std::istringstream iss(line);
            std::string token;
            iss >> token;
            if (token == "VERSION") {
                std::string ver;
                std::getline(iss, ver);
                ver.erase(std::remove(ver.begin(), ver.end(), '"'), ver.end());
                simpleProps["VERSION"] = ver;
            } else if (token == "NS_") {
                inNS = true;
            } else if (inNS && token == "BS_") {
                inNS = false;
                std::string bs;
                std::getline(iss, bs);
                bs.erase(0, bs.find_first_not_of(" :"));
                simpleProps["BS_"] = bs;
            } else if (inNS) {
                listProps["NS_"].push_back(line);
            } else if (token == "BS_:") {
                std::string bs;
                std::getline(iss, bs);
                simpleProps["BS_"] = bs;
            } else if (token == "BU_:") {
                std::string node;
                while (iss >> node) {
                    listProps["BU_"].push_back(node);
                }
            } else if (token == "BO_") {
                currentBO = line;
                listProps["BO_"].push_back(line);
            } else if (token == "SG_" && !currentBO.empty()) {
                std::map<std::string, std::string> sgMap;
                sgMap["message"] = currentBO;
                sgMap["signal"] = line;
                sgProps.push_back(sgMap);
            } else if (token == "CM_") {
                listProps["CM_"].push_back(line);
            } else if (token == "BA_DEF_") {
                listProps["BA_DEF_"].push_back(line);
            } else if (token == "BA_DEF_DEF_") {
                listProps["BA_DEF_DEF_"].push_back(line);
            } else if (token == "BA_") {
                listProps["BA_"].push_back(line);
            } else if (token == "VAL_") {
                listProps["VAL_"].push_back(line);
            } else if (token == "SIG_VALTYPE_") {
                listProps["SIG_VALTYPE_"].push_back(line);
            } else if (token == "BO_TX_BU_") {
                listProps["BO_TX_BU_"].push_back(line);
            } else if (token == "BA_DEF_REL_" || token == "BA_REL_" || token == "BU_SG_REL_") {
                listProps["Relations"].push_back(line);
            }
        }
        file.close();
    }

    void printProperties() const {
        for (const auto& entry : simpleProps) {
            std::cout << entry.first << ":" << std::endl << entry.second << std::endl << std::endl;
        }
        for (const auto& entry : listProps) {
            std::cout << entry.first << ":" << std::endl;
            for (const auto& item : entry.second) {
                std::cout << "- " << item << std::endl;
            }
            std::cout << std::endl;
        }
        std::cout << "SG_:" << std::endl;
        for (const auto& sg : sgProps) {
            std::cout << "- Message: " << sg.at("message") << std::endl;
            std::cout << "  Signal: " << sg.at("signal") << std::endl;
        }
        std::cout << std::endl;
    }

    void write(const std::string& newFilepath = "") const {
        std::string outPath = newFilepath.empty() ? (filepath.empty() ? "output.dbc" : filepath) : newFilepath;
        std::ofstream outFile(outPath);
        if (!outFile.is_open()) {
            throw std::runtime_error("Error writing to file " + outPath);
        }
        if (!simpleProps.at("VERSION").empty()) {
            outFile << "VERSION \"" << simpleProps.at("VERSION") << "\"\n\n";
        }
        if (!listProps.at("NS_").empty()) {
            outFile << "NS_ :\n";
            for (const auto& ns : listProps.at("NS_")) {
                outFile << "  " << ns << "\n";
            }
        }
        if (!simpleProps.at("BS_").empty()) {
            outFile << "\nBS_: " << simpleProps.at("BS_") << "\n";
        }
        if (!listProps.at("BU_").empty()) {
            outFile << "\nBU_: ";
            for (const auto& bu : listProps.at("BU_")) {
                outFile << bu << " ";
            }
            outFile << "\n";
        }
        for (const auto& bo : listProps.at("BO_")) {
            outFile << "\n" << bo << "\n";
            for (const auto& sg : sgProps) {
                if (sg.at("message") == bo) {
                    outFile << " " << sg.at("signal") << "\n";
                }
            }
        }
        for (const auto& cm : listProps.at("CM_")) {
            outFile << "\n" << cm << "\n";
        }
        for (const auto& baDef : listProps.at("BA_DEF_")) {
            outFile << baDef << "\n";
        }
        for (const auto& baDefDef : listProps.at("BA_DEF_DEF_")) {
            outFile << baDefDef << "\n";
        }
        for (const auto& ba : listProps.at("BA_")) {
            outFile << ba << "\n";
        }
        for (const auto& val : listProps.at("VAL_")) {
            outFile << val << "\n";
        }
        for (const auto& sigVal : listProps.at("SIG_VALTYPE_")) {
            outFile << sigVal << "\n";
        }
        for (const auto& boTx : listProps.at("BO_TX_BU_")) {
            outFile << boTx << "\n";
        }
        for (const auto& rel : listProps.at("Relations")) {
            outFile << rel << "\n";
        }
        outFile.close();
    }
};

// Example usage:
// int main() {
//     try {
//         DBCHandler handler("path/to/file.dbc");
//         handler.printProperties();
//         handler.write("path/to/new.dbc");
//     } catch (const std::exception& e) {
//         std::cerr << e.what() << std::endl;
//     }
//     return 0;
// }