Task 613: .RKT File Format

Task 613: .RKT File Format

1. List of all the properties of the .RKT file format intrinsic to its file system

Based on analysis of the RockSim .RKT file format (which is an XML-based structure for rocket design and simulation data), the key properties are derived from its XML elements and hierarchy. These are intrinsic to the format itself and include metadata, design components, and simulation data. The format is ASCII XML, self-documenting, and divided into main sections for design and simulations. Here's the comprehensive list:

  • File Version: The version of the RockSim file format (e.g., under ).
  • Rocket Summary/Design Information: Includes rocket name, designer, revision history, comments, and overall summary (e.g., under ).
  • Rocket Design Structure: The physical design of the rocket, independent of motors or simulations (e.g., under ).
  • Stages: Breakdown by stages (e.g.,  for a typical single-stage or multi-stage setup, with sub-elements for additional stages if present).
  • Parts and Components: Detailed specifications for each part in the rocket design.
  • Nose cone: Shape, length, diameter, material, thickness, position.
  • Body tubes: Length, inner/outer diameter, material, thickness, position.
  • Transitions: Shape, length, fore/aft diameters, material, thickness, position.
  • Fins: Shape (e.g., trapezoid, ellipse), root chord, tip chord, height, sweep, thickness, material, count, position, fillet details.
  • Bulkheads/Centering rings: Diameter, thickness, material, position.
  • Parachutes/Streamers: Diameter/length, material, shroud line details, spill hole, deployment settings.
  • Mass objects: Mass, position, description.
  • Engine mounts/Tubes: Length, diameter, position, overhang.
  • Launch lugs/Buttons: Length, diameter, position, count.
  • Other internal components: Shock cords, attachments, etc.
  • Materials and Finishes: Material types (e.g., balsa, cardboard), density, finish (e.g., painted, roughness).
  • Mass and Stability Properties: Calculated or overridden mass, center of gravity (CG), center of pressure (CP), moments of inertia.
  • Simulation Results List: An array of simulation data (e.g., under , with each  representing one simulation).
  • Simulation Metadata: Simulation name, number (zero-based index), description.
  • Input Parameters: Motor type/configuration, launch rod length/angle, wind speed, temperature, pressure, altitude, latitude.
  • Output Results: Max altitude, max velocity, max acceleration, deployment altitude, time to apogee, ground hit velocity, flight time, data points (time, altitude, velocity arrays).
  • Events: Ignition, burnout, ejection, deployment events with timings.

These properties are extracted from the XML hierarchy, starting from the root .

3. Ghost blog embedded HTML JavaScript for drag-n-drop .RKT file dump

Here's the complete HTML with embedded JavaScript. It allows dragging and dropping a .RKT file, parses it as XML, and dumps all properties (tags, attributes, and text values) to the screen in a hierarchical list.

RKT File Dumper

Drag and Drop .RKT File

Drop .RKT file here

4. Python class for .RKT file handling

import xml.etree.ElementTree as ET
import os

class RKTFileHandler:
    def __init__(self, filename):
        self.filename = filename
        self.tree = None
        self.root = None

    def open_and_decode(self):
        if not os.path.exists(self.filename):
            raise FileNotFoundError(f"File {self.filename} not found.")
        self.tree = ET.parse(self.filename)
        self.root = self.tree.getroot()

    def read_properties(self):
        if self.root is None:
            raise ValueError("File not opened or decoded.")
        properties = {}
        # Extract key sections
        properties['FileVersion'] = self.root.find('FileVersion').text if self.root.find('FileVersion') else 'Unknown'
        design_info = self.root.find('DesignInformation')
        if design_info:
            properties['DesignInformation'] = {child.tag: child.text for child in design_info}
        rocket_design = self.root.find('RocketDesign')
        if rocket_design:
            properties['RocketDesign'] = self._extract_parts(rocket_design)
        sim_list = self.root.find('SimulationResultsList')
        if sim_list:
            properties['SimulationResultsList'] = []
            for sim in sim_list.findall('SimulationResult'):
                sim_data = {child.tag: child.text for child in sim}
                properties['SimulationResultsList'].append(sim_data)
        return properties

    def _extract_parts(self, node):
        parts = {}
        for child in node:
            if child.tag not in parts:
                parts[child.tag] = []
            part_data = {'attributes': dict(child.attrib), 'text': child.text}
            for subchild in child:
                part_data[subchild.tag] = subchild.text
            parts[child.tag].append(part_data)
        return parts

    def print_properties(self):
        props = self.read_properties()
        print("RKT Properties:")
        for key, value in props.items():
            print(f"{key}: {value}")

    def write(self, new_filename=None):
        if self.tree is None:
            raise ValueError("No data to write.")
        filename = new_filename or self.filename
        self.tree.write(filename, encoding='utf-8', xml_declaration=True)

# Example usage:
# handler = RKTFileHandler('example.rkt')
# handler.open_and_decode()
# handler.print_properties()
# handler.write('modified.rkt')

5. Java class for .RKT file handling

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import java.io.File;
import java.util.HashMap;
import java.util.Map;
import java.util.ArrayList;
import java.util.List;

public class RKTFileHandler {
    private String filename;
    private Document doc;

    public RKTFileHandler(String filename) {
        this.filename = filename;
    }

    public void openAndDecode() throws Exception {
        File file = new File(filename);
        DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
        DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
        this.doc = dBuilder.parse(file);
        this.doc.getDocumentElement().normalize();
    }

    public Map<String, Object> readProperties() {
        if (doc == null) {
            throw new IllegalStateException("File not opened or decoded.");
        }
        Map<String, Object> properties = new HashMap<>();
        Element root = doc.getDocumentElement();

        // File Version
        Node versionNode = root.getElementsByTagName("FileVersion").item(0);
        properties.put("FileVersion", versionNode != null ? versionNode.getTextContent() : "Unknown");

        // Design Information
        Node designInfo = root.getElementsByTagName("DesignInformation").item(0);
        if (designInfo != null) {
            properties.put("DesignInformation", extractChildMap((Element) designInfo));
        }

        // Rocket Design
        Node rocketDesign = root.getElementsByTagName("RocketDesign").item(0);
        if (rocketDesign != null) {
            properties.put("RocketDesign", extractParts((Element) rocketDesign));
        }

        // Simulation Results List
        Node simList = root.getElementsByTagName("SimulationResultsList").item(0);
        if (simList != null) {
            List<Map<String, String>> sims = new ArrayList<>();
            NodeList simNodes = ((Element) simList).getElementsByTagName("SimulationResult");
            for (int i = 0; i < simNodes.getLength(); i++) {
                sims.add(extractChildMap((Element) simNodes.item(i)));
            }
            properties.put("SimulationResultsList", sims);
        }
        return properties;
    }

    private Map<String, String> extractChildMap(Element element) {
        Map<String, String> map = new HashMap<>();
        NodeList children = element.getChildNodes();
        for (int i = 0; i < children.getLength(); i++) {
            Node child = children.item(i);
            if (child.getNodeType() == Node.ELEMENT_NODE) {
                map.put(child.getNodeName(), child.getTextContent());
            }
        }
        return map;
    }

    private Map<String, List<Map<String, Object>>> extractParts(Element node) {
        Map<String, List<Map<String, Object>>> parts = new HashMap<>();
        NodeList children = node.getChildNodes();
        for (int i = 0; i < children.getLength(); i++) {
            Node child = children.item(i);
            if (child.getNodeType() == Node.ELEMENT_NODE) {
                Element el = (Element) child;
                String tag = el.getTagName();
                parts.computeIfAbsent(tag, k -> new ArrayList<>());
                Map<String, Object> partData = new HashMap<>();
                for (int j = 0; j < el.getAttributes().getLength(); j++) {
                    Node attr = el.getAttributes().item(j);
                    partData.put(attr.getNodeName(), attr.getNodeValue());
                }
                partData.put("text", el.getTextContent());
                NodeList subChildren = el.getChildNodes();
                for (int k = 0; k < subChildren.getLength(); k++) {
                    Node sub = subChildren.item(k);
                    if (sub.getNodeType() == Node.ELEMENT_NODE) {
                        partData.put(sub.getNodeName(), sub.getTextContent());
                    }
                }
                parts.get(tag).add(partData);
            }
        }
        return parts;
    }

    public void printProperties() {
        try {
            Map<String, Object> props = readProperties();
            System.out.println("RKT Properties:");
            props.forEach((key, value) -> System.out.println(key + ": " + value));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void write(String newFilename) throws Exception {
        if (doc == null) {
            throw new IllegalStateException("No data to write.");
        }
        TransformerFactory transformerFactory = TransformerFactory.newInstance();
        Transformer transformer = transformerFactory.newTransformer();
        DOMSource source = new DOMSource(doc);
        StreamResult result = new StreamResult(new File(newFilename != null ? newFilename : filename));
        transformer.transform(source, result);
    }

    // Example usage:
    // public static void main(String[] args) throws Exception {
    //     RKTFileHandler handler = new RKTFileHandler("example.rkt");
    //     handler.openAndDecode();
    //     handler.printProperties();
    //     handler.write("modified.rkt");
    // }
}

6. JavaScript class for .RKT file handling

class RKTFileHandler {
    constructor(filename) {
        this.filename = filename;
        this.xmlDoc = null;
    }

    async openAndDecode() {
        const response = await fetch(this.filename);
        if (!response.ok) {
            throw new Error(`File ${this.filename} not found.`);
        }
        const xmlText = await response.text();
        const parser = new DOMParser();
        this.xmlDoc = parser.parseFromString(xmlText, 'application/xml');
        if (this.xmlDoc.getElementsByTagName('parsererror').length > 0) {
            throw new Error('Error parsing XML.');
        }
    }

    readProperties() {
        if (!this.xmlDoc) {
            throw new Error('File not opened or decoded.');
        }
        const properties = {};
        const root = this.xmlDoc.documentElement;

        // File Version
        const version = root.querySelector('FileVersion');
        properties.FileVersion = version ? version.textContent : 'Unknown';

        // Design Information
        const designInfo = root.querySelector('DesignInformation');
        if (designInfo) {
            properties.DesignInformation = this._extractChildMap(designInfo);
        }

        // Rocket Design
        const rocketDesign = root.querySelector('RocketDesign');
        if (rocketDesign) {
            properties.RocketDesign = this._extractParts(rocketDesign);
        }

        // Simulation Results List
        const simList = root.querySelector('SimulationResultsList');
        if (simList) {
            properties.SimulationResultsList = [];
            const sims = simList.querySelectorAll('SimulationResult');
            sims.forEach(sim => {
                properties.SimulationResultsList.push(this._extractChildMap(sim));
            });
        }
        return properties;
    }

    _extractChildMap(element) {
        const map = {};
        element.childNodes.forEach(child => {
            if (child.nodeType === Node.ELEMENT_NODE) {
                map[child.tagName] = child.textContent;
            }
        });
        return map;
    }

    _extractParts(node) {
        const parts = {};
        node.childNodes.forEach(child => {
            if (child.nodeType === Node.ELEMENT_NODE) {
                const tag = child.tagName;
                if (!parts[tag]) parts[tag] = [];
                const partData = { attributes: {}, text: child.textContent };
                for (let attr of child.attributes) {
                    partData.attributes[attr.name] = attr.value;
                }
                child.childNodes.forEach(sub => {
                    if (sub.nodeType === Node.ELEMENT_NODE) {
                        partData[sub.tagName] = sub.textContent;
                    }
                });
                parts[tag].push(partData);
            }
        });
        return parts;
    }

    printProperties() {
        const props = this.readProperties();
        console.log('RKT Properties:');
        console.dir(props);
    }

    write(newFilename) {
        if (!this.xmlDoc) {
            throw new Error('No data to write.');
        }
        const serializer = new XMLSerializer();
        const xmlStr = serializer.serializeToString(this.xmlDoc);
        // For browser, this could download; for Node.js, use fs.writeFile
        console.log('Writing to console (simulate write):', xmlStr);
        // To actually write in Node.js: require('fs').writeFileSync(newFilename || this.filename, xmlStr);
    }
}

// Example usage (in browser or Node with fetch polyfill):
// const handler = new RKTFileHandler('example.rkt');
// await handler.openAndDecode();
// handler.printProperties();
// handler.write('modified.rkt');

7. C class for .RKT file handling

Note: C does not have built-in XML parsing like higher-level languages. This implementation assumes use of a simple XML library like Mini-XML (mxml.h), which is lightweight and common for such tasks. If no library is allowed, a full custom parser would be too complex for this scope; assume mxml is available or replace with your preferred lib. The class is written in C++ for object-oriented style (as "c class" likely implies C++).

#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <map>
#include <mxml.h>  // Assume Mini-XML library for parsing

class RKTFileHandler {
private:
    std::string filename;
    mxml_node_t* tree;
    mxml_node_t* root;

public:
    RKTFileHandler(const std::string& fn) : filename(fn), tree(nullptr), root(nullptr) {}

    ~RKTFileHandler() {
        if (tree) mxmlDelete(tree);
    }

    void openAndDecode() {
        FILE* fp = fopen(filename.c_str(), "r");
        if (!fp) {
            throw std::runtime_error("File not found.");
        }
        tree = mxmlLoadFile(fp, MXML_TEXT_CALLBACK);
        fclose(fp);
        if (!tree) {
            throw std::runtime_error("Error parsing XML.");
        }
        root = mxmlFindElement(tree, tree, "RockSimDocument", NULL, NULL, MXML_DESCEND);
        if (!root) {
            throw std::runtime_error("Invalid RKT file.");
        }
    }

    std::map<std::string, std::any> readProperties() {
        if (!root) {
            throw std::runtime_error("File not opened or decoded.");
        }
        std::map<std::string, std::any> properties;

        // File Version
        mxml_node_t* version = mxmlFindElement(root, root, "FileVersion", NULL, NULL, MXML_DESCEND_FIRST);
        properties["FileVersion"] = version ? std::string(mxmlGetText(version, NULL)) : std::string("Unknown");

        // Design Information
        mxml_node_t* designInfo = mxmlFindElement(root, root, "DesignInformation", NULL, NULL, MXML_DESCEND_FIRST);
        if (designInfo) {
            properties["DesignInformation"] = extractChildMap(designInfo);
        }

        // Rocket Design
        mxml_node_t* rocketDesign = mxmlFindElement(root, root, "RocketDesign", NULL, NULL, MXML_DESCEND_FIRST);
        if (rocketDesign) {
            properties["RocketDesign"] = extractParts(rocketDesign);
        }

        // Simulation Results List
        mxml_node_t* simList = mxmlFindElement(root, root, "SimulationResultsList", NULL, NULL, MXML_DESCEND_FIRST);
        if (simList) {
            std::vector<std::map<std::string, std::string>> sims;
            mxml_node_t* sim = mxmlFindElement(simList, simList, "SimulationResult", NULL, NULL, MXML_DESCEND);
            while (sim) {
                sims.push_back(extractChildMap(sim));
                sim = mxmlFindElement(sim, simList, "SimulationResult", NULL, NULL, MXML_NO_DESCEND);
            }
            properties["SimulationResultsList"] = sims;
        }
        return properties;
    }

    std::map<std::string, std::string> extractChildMap(mxml_node_t* node) {
        std::map<std::string, std::string> map;
        mxml_node_t* child = mxmlGetFirstChild(node);
        while (child) {
            if (mxmlGetType(child) == MXML_ELEMENT) {
                map[mxmlGetElement(child)] = std::string(mxmlGetText(child, NULL));
            }
            child = mxmlGetNextSibling(child);
        }
        return map;
    }

    std::map<std::string, std::vector<std::map<std::string, std::any>>> extractParts(mxml_node_t* node) {
        std::map<std::string, std::vector<std::map<std::string, std::any>>> parts;
        mxml_node_t* child = mxmlGetFirstChild(node);
        while (child) {
            if (mxmlGetType(child) == MXML_ELEMENT) {
                std::string tag = mxmlGetElement(child);
                std::map<std::string, std::any> partData;
                // Attributes (Mini-XML attr access)
                const char* attr_name;
                for (int i = 0; (attr_name = mxmlElementGetAttrByIndex(child, i, NULL)); ++i) {
                    partData[attr_name] = std::string(mxmlElementGetAttr(child, attr_name));
                }
                partData["text"] = std::string(mxmlGetText(child, NULL));
                // Subchildren
                mxml_node_t* sub = mxmlGetFirstChild(child);
                while (sub) {
                    if (mxmlGetType(sub) == MXML_ELEMENT) {
                        partData[mxmlGetElement(sub)] = std::string(mxmlGetText(sub, NULL));
                    }
                    sub = mxmlGetNextSibling(sub);
                }
                parts[tag].push_back(partData);
            }
            child = mxmlGetNextSibling(child);
        }
        return parts;
    }

    void printProperties() {
        auto props = readProperties();
        std::cout << "RKT Properties:" << std::endl;
        // Printing is simplified; use recursion or loops for nested maps
        for (const auto& [key, value] : props) {
            std::cout << key << ": [complex value]" << std::endl;  // Expand as needed
        }
    }

    void write(const std::string& newFilename = "") {
        if (!tree) {
            throw std::runtime_error("No data to write.");
        }
        std::string outFile = newFilename.empty() ? filename : newFilename;
        FILE* fp = fopen(outFile.c_str(), "w");
        if (!fp) {
            throw std::runtime_error("Cannot write file.");
        }
        mxmlSaveFile(tree, fp, MXML_NO_CALLBACK);
        fclose(fp);
    }
};

// Example usage:
// int main() {
//     try {
//         RKTFileHandler handler("example.rkt");
//         handler.openAndDecode();
//         handler.printProperties();
//         handler.write("modified.rkt");
//     } catch (const std::exception& e) {
//         std::cerr << e.what() << std::endl;
//     }
//     return 0;
// }