Task 824: .X File Format

Task 824: .X File Format

The .X file format refers to the legacy Microsoft DirectX .X format used for 3D graphics data such as meshes, animations, and materials. It supports both text and binary encodings, with optional compression, and is template-driven for extensibility.

The properties intrinsic to the .X file format (from the fixed header structure common to all .X files) are:

  • Magic number: A 4-byte string "xof " indicating the start of the file.
  • Major version: A 2-byte ASCII string representing the major version number (e.g., "03" for version 3).
  • Minor version: A 2-byte ASCII string representing the minor version number (e.g., "02").
  • Format type: A 4-byte string indicating the encoding ("txt " for text, "bin " for binary, "tzip" for compressed text, "bzip" for compressed binary).
  • Float size: A 4-byte ASCII string indicating the precision of floating-point numbers ("0032" for 32-bit floats, "0064" for 64-bit floats).

Two direct download links for sample .X files:

HTML/JavaScript for drag-and-drop .X file parsing (embeddable in a Ghost blog post or similar; it reads the file as binary, extracts the header properties, and dumps them to the screen):

.X File Header Dumper
Drag and drop a .X file here

    

  1. Python class for handling .X files (reads header properties, prints them; also supports writing a minimal .X file with custom header values):
import struct

class XFileHandler:
    def __init__(self):
        self.magic = b'xof '
        self.major = b'03'
        self.minor = b'02'
        self.format_type = b'txt '
        self.float_size = b'0032'

    def read(self, filename):
        with open(filename, 'rb') as f:
            data = f.read(16)
            self.magic = data[0:4]
            self.major = data[4:6]
            self.minor = data[6:8]
            self.format_type = data[8:12]
            self.float_size = data[12:16]
            self.print_properties()

    def print_properties(self):
        print(f"Magic number: {self.magic.decode('utf-8')}")
        print(f"Major version: {self.major.decode('utf-8')}")
        print(f"Minor version: {self.minor.decode('utf-8')}")
        print(f"Format type: {self.format_type.decode('utf-8')}")
        print(f"Float size: {self.float_size.decode('utf-8')}")

    def write(self, filename, magic=b'xof ', major=b'03', minor=b'02', format_type=b'txt ', float_size=b'0032'):
        header = magic + major + minor + format_type + float_size
        with open(filename, 'wb') as f:
            f.write(header)
            # Minimal content (e.g., empty template for a valid but empty file)
            f.write(b'template Empty {}')

# Example usage:
# handler = XFileHandler()
# handler.read('sample.x')
# handler.write('output.x')
  1. Java class for handling .X files (reads header properties, prints them; also supports writing a minimal .X file with custom header values):
import java.io.*;
import java.nio.charset.StandardCharsets;

public class XFileHandler {
    private String magic;
    private String major;
    private String minor;
    private String formatType;
    private String floatSize;

    public void read(String filename) throws IOException {
        try (FileInputStream fis = new FileInputStream(filename)) {
            byte[] header = new byte[16];
            fis.read(header);
            magic = new String(header, 0, 4, StandardCharsets.UTF_8);
            major = new String(header, 4, 2, StandardCharsets.UTF_8);
            minor = new String(header, 6, 2, StandardCharsets.UTF_8);
            formatType = new String(header, 8, 4, StandardCharsets.UTF_8);
            floatSize = new String(header, 12, 4, StandardCharsets.UTF_8);
            printProperties();
        }
    }

    public void printProperties() {
        System.out.println("Magic number: " + magic);
        System.out.println("Major version: " + major);
        System.out.println("Minor version: " + minor);
        System.out.println("Format type: " + formatType);
        System.out.println("Float size: " + floatSize);
    }

    public void write(String filename, String magic, String major, String minor, String formatType, String floatSize) throws IOException {
        byte[] header = (magic + major + minor + formatType + floatSize).getBytes(StandardCharsets.UTF_8);
        try (FileOutputStream fos = new FileOutputStream(filename)) {
            fos.write(header);
            // Minimal content (e.g., empty template for a valid but empty file)
            fos.write("template Empty {}".getBytes(StandardCharsets.UTF_8));
        }
    }

    // Example usage:
    // public static void main(String[] args) throws IOException {
    //     XFileHandler handler = new XFileHandler();
    //     handler.read("sample.x");
    //     handler.write("output.x", "xof ", "03", "02", "txt ", "0032");
    // }
}
  1. JavaScript class for handling .X files (reads header properties from a buffer, prints them to console; also supports writing a minimal .X file buffer):
class XFileHandler {
    constructor() {}

    read(buffer) {
        const view = new DataView(buffer);
        const decoder = new TextDecoder('utf-8');
        this.magic = decoder.decode(new Uint8Array(buffer, 0, 4));
        this.major = decoder.decode(new Uint8Array(buffer, 4, 2));
        this.minor = decoder.decode(new Uint8Array(buffer, 6, 2));
        this.formatType = decoder.decode(new Uint8Array(buffer, 8, 4));
        this.floatSize = decoder.decode(new Uint8Array(buffer, 12, 4));
        this.printProperties();
    }

    printProperties() {
        console.log(`Magic number: ${this.magic}`);
        console.log(`Major version: ${this.major}`);
        console.log(`Minor version: ${this.minor}`);
        console.log(`Format type: ${this.formatType}`);
        console.log(`Float size: ${this.floatSize}`);
    }

    write(magic = 'xof ', major = '03', minor = '02', formatType = 'txt ', floatSize = '0032') {
        const encoder = new TextEncoder();
        const header = encoder.encode(magic + major + minor + formatType + floatSize);
        const content = encoder.encode('template Empty {}'); // Minimal content
        const fullBuffer = new Uint8Array(header.length + content.length);
        fullBuffer.set(header, 0);
        fullBuffer.set(content, header.length);
        return fullBuffer; // Return buffer for e.g., Blob or download
    }
}

// Example usage (assuming buffer from FileReader):
// const handler = new XFileHandler();
// handler.read(arrayBuffer);
// const newBuffer = handler.write();
  1. C implementation (using struct instead of class, as C lacks classes; reads header properties, prints them; also supports writing a minimal .X file with custom header values):
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct {
    char magic[5];
    char major[3];
    char minor[3];
    char format_type[5];
    char float_size[5];
} XFileHeader;

void read_xfile(const char* filename, XFileHeader* header) {
    FILE* file = fopen(filename, "rb");
    if (file) {
        char buffer[16];
        fread(buffer, 1, 16, file);
        strncpy(header->magic, buffer, 4);
        header->magic[4] = '\0';
        strncpy(header->major, buffer + 4, 2);
        header->major[2] = '\0';
        strncpy(header->minor, buffer + 6, 2);
        header->minor[2] = '\0';
        strncpy(header->format_type, buffer + 8, 4);
        header->format_type[4] = '\0';
        strncpy(header->float_size, buffer + 12, 4);
        header->float_size[4] = '\0';
        fclose(file);
        print_properties(header);
    } else {
        printf("Failed to open file.\n");
    }
}

void print_properties(const XFileHeader* header) {
    printf("Magic number: %s\n", header->magic);
    printf("Major version: %s\n", header->major);
    printf("Minor version: %s\n", header->minor);
    printf("Format type: %s\n", header->format_type);
    printf("Float size: %s\n", header->float_size);
}

void write_xfile(const char* filename, const char* magic, const char* major, const char* minor, const char* format_type, const char* float_size) {
    FILE* file = fopen(filename, "wb");
    if (file) {
        fwrite(magic, 1, 4, file);
        fwrite(major, 1, 2, file);
        fwrite(minor, 1, 2, file);
        fwrite(format_type, 1, 4, file);
        fwrite(float_size, 1, 4, file);
        // Minimal content (e.g., empty template for a valid but empty file)
        const char* content = "template Empty {}";
        fwrite(content, 1, strlen(content), file);
        fclose(file);
    } else {
        printf("Failed to open file for writing.\n");
    }
}

// Example usage:
// int main() {
//     XFileHeader header;
//     read_xfile("sample.x", &header);
//     write_xfile("output.x", "xof ", "03", "02", "txt ", "0032");
//     return 0;
// }