Task 306: .IFC File Format

Task 306: .IFC File Format

1. List of Properties Intrinsic to the .IFC File Format

The .IFC (Industry Foundation Classes) file format is an open standard for Building Information Modeling (BIM) data, based on the ISO 10303-21 (STEP) physical file structure. It is a text-based format that starts with a mandatory HEADER section containing metadata about the file. The intrinsic properties are primarily defined in this HEADER, which includes three main entities: FILE_DESCRIPTION, FILE_NAME, and FILE_SCHEMA. These properties provide essential file metadata, such as version, origin, and schema details. The file always begins with the magic string "ISO-10303-21;" and ends with "END-ISO-10303-21;". The HEADER section is delimited by "HEADER;" and "ENDSEC;".

Based on the official specifications and examples from buildingSMART and sample files, the complete list of intrinsic properties is:

  • Description: A list of strings describing the file's view definitions or comments (e.g., 'ViewDefinition [CoordinationView]', 'Comment [Example IFC file]').
  • Implementation Level: A string indicating the STEP implementation level (typically '2;1' for IFC files).
  • File Name: The original name of the file as a string (e.g., 'example.ifc').
  • Time Stamp: A string representing the creation or export time in ISO format (e.g., '2020-12-18T08:58:25').
  • Author: A list of strings for the author(s) (e.g., ('John Doe')).
  • Organization: A list of strings for the organization(s) (e.g., ('Acme Corp')).
  • Preprocessor Version: A string for the software version used to preprocess the file (e.g., 'IFC Export Tool v1.0').
  • Originating System: A string identifying the software that created the file (e.g., 'Revit 2024').
  • Authorization: A string for the authorizing person or entity (often empty or a name).
  • Schema: A list of strings specifying the IFC schema version (e.g., ('IFC4'), ('IFC2X3'), or ('IFC4X3_RC3')).

These properties are mandatory in the HEADER and are used for validation, interoperability, and context when exchanging BIM data.

Here are two direct download links to sample .IFC files:

3. Ghost Blog Embedded HTML JavaScript for Drag-and-Drop .IFC File Dump

Below is a standalone HTML page with embedded JavaScript that can be embedded in a Ghost blog (or any HTML-supported platform). It allows users to drag and drop an .IFC file, parses the HEADER section, extracts the properties listed in point 1, and dumps them to the screen in a readable format.

IFC File Property Dumper

Drag and Drop .IFC File to Dump Properties

Drop .IFC file here

4. Python Class for .IFC File Handling

Below is a Python class that can open, read, decode (parse) the HEADER properties, print them to console, and write a modified version of the file (e.g., updating properties).

import re

class IFCFileHandler:
    def __init__(self, filepath):
        self.filepath = filepath
        self.properties = {}
        self.full_text = ''
        self.header = ''
        self.read_and_decode()

    def read_and_decode(self):
        with open(self.filepath, 'r', encoding='utf-8') as f:
            self.full_text = f.read()
        if not self.full_text.startswith('ISO-10303-21;'):
            raise ValueError('Invalid .IFC file: Missing magic string.')
        header_start = self.full_text.find('HEADER;')
        header_end = self.full_text.find('ENDSEC;', header_start)
        if header_start == -1 or header_end == -1:
            raise ValueError('Invalid .IFC file: Missing HEADER section.')
        self.header = self.full_text[header_start + 7:header_end].strip()

        file_desc_match = re.search(r"FILE_DESCRIPTION\(\((.*?)\),'([\d;]+)'\);", self.header, re.DOTALL)
        file_name_match = re.search(r"FILE_NAME\('(.*?)','(.*?)',\((.*?)\),\((.*?)\),'(.*?)','(.*?)','(.*?)'", self.header, re.DOTALL)
        file_schema_match = re.search(r"FILE_SCHEMA\(\((.*?)\)\);", self.header, re.DOTALL)

        if file_desc_match:
            self.properties['Description'] = file_desc_match.group(1).replace("'", "").split(',')
            self.properties['Implementation Level'] = file_desc_match.group(2)
        if file_name_match:
            self.properties['File Name'] = file_name_match.group(1)
            self.properties['Time Stamp'] = file_name_match.group(2)
            self.properties['Author'] = file_name_match.group(3).replace("'", "").split(',')
            self.properties['Organization'] = file_name_match.group(4).replace("'", "").split(',')
            self.properties['Preprocessor Version'] = file_name_match.group(5)
            self.properties['Originating System'] = file_name_match.group(6)
            self.properties['Authorization'] = file_name_match.group(7)
        if file_schema_match:
            self.properties['Schema'] = file_schema_match.group(1).replace("'", "").split(',')

    def print_properties(self):
        for key, value in self.properties.items():
            print(f"{key}: {value}")

    def update_property(self, key, new_value):
        if key in self.properties:
            self.properties[key] = new_value

    def write(self, output_path):
        new_header = self._build_header()
        new_text = self.full_text.replace(self.header, new_header)
        with open(output_path, 'w', encoding='utf-8') as f:
            f.write(new_text)

    def _build_header(self):
        desc = ','.join(f"'{d}'" for d in self.properties.get('Description', []))
        impl_level = self.properties.get('Implementation Level', '2;1')
        file_desc = f"FILE_DESCRIPTION(({desc}),'{impl_level}');"

        name = self.properties.get('File Name', '')
        timestamp = self.properties.get('Time Stamp', '')
        author = ','.join(f"'{a}'" for a in self.properties.get('Author', []))
        org = ','.join(f"'{o}'" for o in self.properties.get('Organization', []))
        prep_ver = self.properties.get('Preprocessor Version', '')
        orig_sys = self.properties.get('Originating System', '')
        auth = self.properties.get('Authorization', '')
        file_name = f"FILE_NAME('{name}','{timestamp}',({author}),({org}),'{prep_ver}','{orig_sys}','{auth}');"

        schema = ','.join(f"'{s}'" for s in self.properties.get('Schema', []))
        file_schema = f"FILE_SCHEMA(({schema}));"

        return f"{file_desc}\n{file_name}\n{file_schema}"

# Example usage:
# handler = IFCFileHandler('example.ifc')
# handler.print_properties()
# handler.update_property('Time Stamp', '2025-09-27T12:00:00')
# handler.write('modified.ifc')

5. Java Class for .IFC File Handling

Below is a Java class that performs similar operations: open, read, decode, print properties, and write modified file.

import java.io.*;
import java.util.*;
import java.util.regex.*;

public class IFCFileHandler {
    private String filepath;
    private Map<String, Object> properties = new HashMap<>();
    private String fullText = "";
    private String header = "";

    public IFCFileHandler(String filepath) {
        this.filepath = filepath;
        readAndDecode();
    }

    private void readAndDecode() {
        try (BufferedReader reader = new BufferedReader(new FileReader(filepath))) {
            StringBuilder sb = new StringBuilder();
            String line;
            while ((line = reader.readLine()) != null) {
                sb.append(line).append("\n");
            }
            fullText = sb.toString();
        } catch (IOException e) {
            throw new RuntimeException("Error reading file", e);
        }

        if (!fullText.startsWith("ISO-10303-21;")) {
            throw new IllegalArgumentException("Invalid .IFC file: Missing magic string.");
        }
        int headerStart = fullText.indexOf("HEADER;");
        int headerEnd = fullText.indexOf("ENDSEC;", headerStart);
        if (headerStart == -1 || headerEnd == -1) {
            throw new IllegalArgumentException("Invalid .IFC file: Missing HEADER section.");
        }
        header = fullText.substring(headerStart + 7, headerEnd).trim();

        Pattern fileDescPattern = Pattern.compile("FILE_DESCRIPTION\\(\\((.*?)\\),'([\\d;]+)'\\);", Pattern.DOTALL);
        Matcher fileDescMatcher = fileDescPattern.matcher(header);
        if (fileDescMatcher.find()) {
            properties.put("Description", Arrays.asList(fileDescMatcher.group(1).replace("'", "").split(",")));
            properties.put("Implementation Level", fileDescMatcher.group(2));
        }

        Pattern fileNamePattern = Pattern.compile("FILE_NAME\\('(.*?)','(.*?)',\\((.*?)\\),\\((.*?)\\),'(.*?)','(.*?)','(.*?)'", Pattern.DOTALL);
        Matcher fileNameMatcher = fileNamePattern.matcher(header);
        if (fileNameMatcher.find()) {
            properties.put("File Name", fileNameMatcher.group(1));
            properties.put("Time Stamp", fileNameMatcher.group(2));
            properties.put("Author", Arrays.asList(fileNameMatcher.group(3).replace("'", "").split(",")));
            properties.put("Organization", Arrays.asList(fileNameMatcher.group(4).replace("'", "").split(",")));
            properties.put("Preprocessor Version", fileNameMatcher.group(5));
            properties.put("Originating System", fileNameMatcher.group(6));
            properties.put("Authorization", fileNameMatcher.group(7));
        }

        Pattern fileSchemaPattern = Pattern.compile("FILE_SCHEMA\\(\\((.*?)\\)\\);", Pattern.DOTALL);
        Matcher fileSchemaMatcher = fileSchemaPattern.matcher(header);
        if (fileSchemaMatcher.find()) {
            properties.put("Schema", Arrays.asList(fileSchemaMatcher.group(1).replace("'", "").split(",")));
        }
    }

    public void printProperties() {
        for (Map.Entry<String, Object> entry : properties.entrySet()) {
            System.out.println(entry.getKey() + ": " + entry.getValue());
        }
    }

    public void updateProperty(String key, Object newValue) {
        if (properties.containsKey(key)) {
            properties.put(key, newValue);
        }
    }

    public void write(String outputPath) {
        String newHeader = buildHeader();
        String newText = fullText.replace(header, newHeader);
        try (BufferedWriter writer = new BufferedWriter(new FileWriter(outputPath))) {
            writer.write(newText);
        } catch (IOException e) {
            throw new RuntimeException("Error writing file", e);
        }
    }

    private String buildHeader() {
        @SuppressWarnings("unchecked")
        List<String> desc = (List<String>) properties.getOrDefault("Description", new ArrayList<>());
        String implLevel = (String) properties.getOrDefault("Implementation Level", "2;1");
        String fileDesc = "FILE_DESCRIPTION((" + String.join(",", desc.stream().map(d -> "'" + d + "'").toArray()) + "),'" + implLevel + "');";

        String name = (String) properties.getOrDefault("File Name", "");
        String timestamp = (String) properties.getOrDefault("Time Stamp", "");
        @SuppressWarnings("unchecked")
        List<String> author = (List<String>) properties.getOrDefault("Author", new ArrayList<>());
        @SuppressWarnings("unchecked")
        List<String> org = (List<String>) properties.getOrDefault("Organization", new ArrayList<>());
        String prepVer = (String) properties.getOrDefault("Preprocessor Version", "");
        String origSys = (String) properties.getOrDefault("Originating System", "");
        String auth = (String) properties.getOrDefault("Authorization", "");
        String fileName = "FILE_NAME('" + name + "','" + timestamp + "',(" + String.join(",", author.stream().map(a -> "'" + a + "'").toArray()) + "),(" + String.join(",", org.stream().map(o -> "'" + o + "'").toArray()) + "),'" + prepVer + "','" + origSys + "','" + auth + "');";

        @SuppressWarnings("unchecked")
        List<String> schema = (List<String>) properties.getOrDefault("Schema", new ArrayList<>());
        String fileSchema = "FILE_SCHEMA((" + String.join(",", schema.stream().map(s -> "'" + s + "'").toArray()) + "));";

        return fileDesc + "\n" + fileName + "\n" + fileSchema;
    }

    // Example usage:
    // public static void main(String[] args) {
    //     IFCFileHandler handler = new IFCFileHandler("example.ifc");
    //     handler.printProperties();
    //     handler.updateProperty("Time Stamp", "2025-09-27T12:00:00");
    //     handler.write("modified.ifc");
    // }
}

6. JavaScript Class for .IFC File Handling

Below is a Node.js JavaScript class (using fs module) for opening, reading, decoding, printing properties to console, and writing modified files.

const fs = require('fs');

class IFCFileHandler {
    constructor(filepath) {
        this.filepath = filepath;
        this.properties = {};
        this.fullText = '';
        this.header = '';
        this.readAndDecode();
    }

    readAndDecode() {
        this.fullText = fs.readFileSync(this.filepath, 'utf-8');
        if (!this.fullText.startsWith('ISO-10303-21;')) {
            throw new Error('Invalid .IFC file: Missing magic string.');
        }
        const headerStart = this.fullText.indexOf('HEADER;');
        const headerEnd = this.fullText.indexOf('ENDSEC;', headerStart);
        if (headerStart === -1 || headerEnd === -1) {
            throw new Error('Invalid .IFC file: Missing HEADER section.');
        }
        this.header = this.fullText.substring(headerStart + 7, headerEnd).trim();

        const fileDescMatch = this.header.match(/FILE_DESCRIPTION\(\((.*?)\),'([\d;]+)'\);/s);
        const fileNameMatch = this.header.match(/FILE_NAME\('(.*?)','(.*?)',\((.*?)\),\((.*?)\),'(.*?)','(.*?)','(.*?)'/s);
        const fileSchemaMatch = this.header.match(/FILE_SCHEMA\(\((.*?)\)\);/s);

        if (fileDescMatch) {
            this.properties['Description'] = fileDescMatch[1].replace(/'/g, '').split(',');
            this.properties['Implementation Level'] = fileDescMatch[2];
        }
        if (fileNameMatch) {
            this.properties['File Name'] = fileNameMatch[1];
            this.properties['Time Stamp'] = fileNameMatch[2];
            this.properties['Author'] = fileNameMatch[3].replace(/'/g, '').split(',');
            this.properties['Organization'] = fileNameMatch[4].replace(/'/g, '').split(',');
            this.properties['Preprocessor Version'] = fileNameMatch[5];
            this.properties['Originating System'] = fileNameMatch[6];
            this.properties['Authorization'] = fileNameMatch[7];
        }
        if (fileSchemaMatch) {
            this.properties['Schema'] = fileSchemaMatch[1].replace(/'/g, '').split(',');
        }
    }

    printProperties() {
        for (const [key, value] of Object.entries(this.properties)) {
            console.log(`${key}: ${Array.isArray(value) ? value.join(', ') : value}`);
        }
    }

    updateProperty(key, newValue) {
        if (key in this.properties) {
            this.properties[key] = newValue;
        }
    }

    write(outputPath) {
        const newHeader = this._buildHeader();
        const newText = this.fullText.replace(this.header, newHeader);
        fs.writeFileSync(outputPath, newText, 'utf-8');
    }

    _buildHeader() {
        const desc = this.properties['Description']?.map(d => `'${d}'`).join(',') || '';
        const implLevel = this.properties['Implementation Level'] || '2;1';
        const fileDesc = `FILE_DESCRIPTION((${desc}),'${implLevel}');`;

        const name = this.properties['File Name'] || '';
        const timestamp = this.properties['Time Stamp'] || '';
        const author = this.properties['Author']?.map(a => `'${a}'`).join(',') || '';
        const org = this.properties['Organization']?.map(o => `'${o}'`).join(',') || '';
        const prepVer = this.properties['Preprocessor Version'] || '';
        const origSys = this.properties['Originating System'] || '';
        const auth = this.properties['Authorization'] || '';
        const fileName = `FILE_NAME('${name}','${timestamp}',(${author}),(${org}),'${prepVer}','${origSys}','${auth}');`;

        const schema = this.properties['Schema']?.map(s => `'${s}'`).join(',') || '';
        const fileSchema = `FILE_SCHEMA((${schema}));`;

        return `${fileDesc}\n${fileName}\n${fileSchema}`;
    }
}

// Example usage:
// const handler = new IFCFileHandler('example.ifc');
// handler.printProperties();
// handler.updateProperty('Time Stamp', '2025-09-27T12:00:00');
// handler.write('modified.ifc');

7. C++ Class for .IFC File Handling

Below is a C++ class (using standard library) for opening, reading, decoding, printing properties to console, and writing modified files.

#include <iostream>
#include <fstream>
#include <sstream>
#include <vector>
#include <map>
#include <regex>
#include <string>

class IFCFileHandler {
private:
    std::string filepath;
    std::map<std::string, std::vector<std::string>> properties; // Use vector for lists
    std::string fullText;
    std::string header;

public:
    IFCFileHandler(const std::string& fp) : filepath(fp) {
        readAndDecode();
    }

    void readAndDecode() {
        std::ifstream file(filepath);
        if (!file) {
            throw std::runtime_error("Error opening file");
        }
        std::stringstream buffer;
        buffer << file.rdbuf();
        fullText = buffer.str();

        if (fullText.find("ISO-10303-21;") != 0) {
            throw std::invalid_argument("Invalid .IFC file: Missing magic string.");
        }
        size_t headerStart = fullText.find("HEADER;");
        size_t headerEnd = fullText.find("ENDSEC;", headerStart);
        if (headerStart == std::string::npos || headerEnd == std::string::npos) {
            throw std::invalid_argument("Invalid .IFC file: Missing HEADER section.");
        }
        header = fullText.substr(headerStart + 7, headerEnd - headerStart - 7);

        std::regex fileDescRegex(R"(FILE_DESCRIPTION\(\((.*?)\),'([\d;]+)'\);)");
        std::smatch fileDescMatch;
        if (std::regex_search(header, fileDescMatch, fileDescRegex)) {
            std::string descStr = fileDescMatch[1].str();
            std::vector<std::string> desc;
            std::regex descItem(R"('(.*?)')");
            std::sregex_iterator iter(descStr.begin(), descStr.end(), descItem);
            for (; iter != std::sregex_iterator(); ++iter) {
                desc.push_back((*iter)[1].str());
            }
            properties["Description"] = desc;
            properties["Implementation Level"] = {fileDescMatch[2].str()};
        }

        std::regex fileNameRegex(R"(FILE_NAME\('(.*?)','(.*?)',\((.*?)\),\((.*?)\),'(.*?)','(.*?)','(.*?)'(.*))");
        std::smatch fileNameMatch;
        if (std::regex_search(header, fileNameMatch, fileNameRegex)) {
            properties["File Name"] = {fileNameMatch[1].str()};
            properties["Time Stamp"] = {fileNameMatch[2].str()};
            std::string authorStr = fileNameMatch[3].str();
            std::vector<std::string> authors;
            std::sregex_iterator aIter(authorStr.begin(), authorStr.end(), descItem);
            for (; aIter != std::sregex_iterator(); ++aIter) {
                authors.push_back((*aIter)[1].str());
            }
            properties["Author"] = authors;
            std::string orgStr = fileNameMatch[4].str();
            std::vector<std::string> orgs;
            std::sregex_iterator oIter(orgStr.begin(), orgStr.end(), descItem);
            for (; oIter != std::sregex_iterator(); ++oIter) {
                orgs.push_back((*oIter)[1].str());
            }
            properties["Organization"] = orgs;
            properties["Preprocessor Version"] = {fileNameMatch[5].str()};
            properties["Originating System"] = {fileNameMatch[6].str()};
            properties["Authorization"] = {fileNameMatch[7].str()};
        }

        std::regex fileSchemaRegex(R"(FILE_SCHEMA\(\((.*?)\)\);)");
        std::smatch fileSchemaMatch;
        if (std::regex_search(header, fileSchemaMatch, fileSchemaRegex)) {
            std::string schemaStr = fileSchemaMatch[1].str();
            std::vector<std::string> schemas;
            std::sregex_iterator sIter(schemaStr.begin(), schemaStr.end(), descItem);
            for (; sIter != std::sregex_iterator(); ++sIter) {
                schemas.push_back((*sIter)[1].str());
            }
            properties["Schema"] = schemas;
        }
    }

    void printProperties() const {
        for (const auto& pair : properties) {
            std::cout << pair.first << ": ";
            for (size_t i = 0; i < pair.second.size(); ++i) {
                std::cout << pair.second[i];
                if (i < pair.second.size() - 1) std::cout << ", ";
            }
            std::cout << std::endl;
        }
    }

    void updateProperty(const std::string& key, const std::vector<std::string>& newValue) {
        if (properties.count(key)) {
            properties[key] = newValue;
        }
    }

    void write(const std::string& outputPath) {
        std::string newHeader = buildHeader();
        std::string newText = fullText;
        newText.replace(fullText.find(header), header.length(), newHeader);
        std::ofstream outFile(outputPath);
        if (!outFile) {
            throw std::runtime_error("Error writing file");
        }
        outFile << newText;
    }

private:
    std::string buildHeader() const {
        std::string fileDesc;
        auto it = properties.find("Description");
        if (it != properties.end()) {
            std::string desc;
            for (const auto& d : it->second) {
                if (!desc.empty()) desc += ",";
                desc += "'" + d + "'";
            }
            auto implIt = properties.find("Implementation Level");
            std::string impl = (implIt != properties.end() && !implIt->second.empty()) ? implIt->second[0] : "2;1";
            fileDesc = "FILE_DESCRIPTION((" + desc + "),'" + impl + "');";
        }

        std::string fileName;
        std::string name = (properties.count("File Name") && !properties.at("File Name").empty()) ? properties.at("File Name")[0] : "";
        std::string timestamp = (properties.count("Time Stamp") && !properties.at("Time Stamp").empty()) ? properties.at("Time Stamp")[0] : "";
        std::string author;
        if (properties.count("Author")) {
            for (const auto& a : properties.at("Author")) {
                if (!author.empty()) author += ",";
                author += "'" + a + "'";
            }
        }
        std::string org;
        if (properties.count("Organization")) {
            for (const auto& o : properties.at("Organization")) {
                if (!org.empty()) org += ",";
                org += "'" + o + "'";
            }
        }
        std::string prepVer = (properties.count("Preprocessor Version") && !properties.at("Preprocessor Version").empty()) ? properties.at("Preprocessor Version")[0] : "";
        std::string origSys = (properties.count("Originating System") && !properties.at("Originating System").empty()) ? properties.at("Originating System")[0] : "";
        std::string auth = (properties.count("Authorization") && !properties.at("Authorization").empty()) ? properties.at("Authorization")[0] : "";
        fileName = "FILE_NAME('" + name + "','" + timestamp + "',(" + author + "),(" + org + "),'" + prepVer + "','" + origSys + "','" + auth + "');";

        std::string fileSchema;
        it = properties.find("Schema");
        if (it != properties.end()) {
            std::string schema;
            for (const auto& s : it->second) {
                if (!schema.empty()) schema += ",";
                schema += "'" + s + "'";
            }
            fileSchema = "FILE_SCHEMA((" + schema + "));";
        }

        return fileDesc + "\n" + fileName + "\n" + fileSchema;
    }
};

// Example usage:
// int main() {
//     try {
//         IFCFileHandler handler("example.ifc");
//         handler.printProperties();
//         handler.updateProperty("Time Stamp", {"2025-09-27T12:00:00"});
//         handler.write("modified.ifc");
//     } catch (const std::exception& e) {
//         std::cerr << e.what() << std::endl;
//     }
//     return 0;
// }