Task 315: .IQBLOCKS File Format

Task 315: .IQBLOCKS File Format

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

The .IQBLOCKS file format is used by VEXcode IQ Blocks, a graphical programming environment for VEX IQ robots, powered by Scratch Blocks. The format is a text-based JSON file that stores the project data, including the workspace state, device configuration, blocks, variables, and other elements. It is not a binary format or zip archive; it is a plain JSON file that can be opened with any text editor. The intrinsic properties (top-level JSON keys and their typical contents) are as follows, based on the structure derived from Scratch Blocks serialization adapted for VEX:

  • meta: Object containing metadata about the project, such as "vm" (virtual machine version), "agent" (user agent string), and "semver" (semantic version of the format, e.g., "3.0.0").
  • targets: Array of objects representing the robot "targets" (e.g., stage or sprites, but in VEX context, the robot brain and components). Each target object includes:
  • "isStage": Boolean indicating if it's the main stage.
  • "name": String for the target name (e.g., "Robot").
  • "variables": Object mapping variable IDs to arrays with name and value (e.g., {"id1": ["myVariable", 0]}).
  • "lists": Object for lists, similar to variables but with array values.
  • "broadcasts": Object for message broadcasts.
  • "blocks": Object mapping block IDs to block definitions, including type, opcode, next, parent, inputs, fields, shadow, topLevel, x, y, etc. (e.g., a "driveForward" block with parameters).
  • "comments": Object for attached comments.
  • "currentCostume": Integer for current asset index.
  • "costumes": Array of asset objects (e.g., for robot visuals).
  • "sounds": Array of sound assets.
  • "volume": Integer for sound volume.
  • "layerOrder": Integer for layering.
  • monitors: Array of monitor objects for displayed variables or lists, with properties like id, mode, opcode, params, spriteName, value, width, height, x, y, visible.
  • extensions: Array of strings for enabled extensions (e.g., ["vex_iq"] for VEX-specific blocks).
  • extensionSettings: Object for extension configurations.
  • device: Object specific to VEX, containing robot configuration like ports for motors and sensors (e.g., {"motors": {"port1": "leftMotor"}, "sensors": {"port12": "gyro"}}).
  • projectName: String for the project name (optional, sometimes stored in meta).

These properties define the file's structure, allowing the VEXcode software to load the graphical blocks, robot setup, and code logic.

  1. https://content.vexrobotics.com/assets/education/stem-labs/docs/iq/iq_stem_labs/VIQC Virtual Skills/VIQRC Full Volume/Lesson 3_ Autonomous Coding Skills/Byte Template.iqblocks (Byte Template for autonomous coding in VEX IQ STEM Lab)
  2. https://git.krasnikov.pro/Lab/robotop.krasnikov.pro/raw/branch/master/public/blog/robot_builds/short_track_vex_iq/linePD.iqblocks (Line PD example for short track VEX IQ robot)

3. Ghost blog embedded html javascript that allows a user to drag n drop a file of format .IQBLOCKS and it will dump to screen all these properties

IQBLOCKS Viewer

Drag and Drop .IQBLOCKS File Viewer

Drag and drop your .IQBLOCKS file here

4. Python class that can open any file of format .IQBLOCKS and decode read and write and print to console all the properties from the above list

import json
import os

class IQBlocksHandler:
    def __init__(self, filepath):
        self.filepath = filepath
        self.data = None

    def read(self):
        if not os.path.exists(self.filepath):
            raise FileNotFoundError(f"File {self.filepath} not found.")
        with open(self.filepath, 'r') as f:
            self.data = json.load(f)
        return self.data

    def print_properties(self):
        if self.data is None:
            self.read()
        print("Properties from .IQBLOCKS file:")
        for key, value in self.data.items():
            print(f"{key}: {type(value).__name__} - Example: {str(value)[:100]}...")  # Truncated for brevity

    def write(self, new_data=None):
        if new_data is not None:
            self.data = new_data
        if self.data is None:
            raise ValueError("No data to write.")
        with open(self.filepath, 'w') as f:
            json.dump(self.data, f, indent=4)
        print(f"File written to {self.filepath}")

# Example usage:
# handler = IQBlocksHandler('example.iqblocks')
# handler.read()
# handler.print_properties()
# handler.write({'meta': {'new': 'data'}})

5. Java class that can open any file of format .IQBLOCKS and decode read and write and print to console all the properties from the above list

import com.google.gson.Gson;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Map;

public class IQBlocksHandler {
    private String filepath;
    private JsonObject data;

    public IQBlocksHandler(String filepath) {
        this.filepath = filepath;
        this.data = null;
    }

    public JsonObject read() throws IOException {
        try (FileReader reader = new FileReader(filepath)) {
            this.data = JsonParser.parseReader(reader).getAsJsonObject();
        }
        return this.data;
    }

    public void printProperties() throws IOException {
        if (data == null) {
            read();
        }
        System.out.println("Properties from .IQBLOCKS file:");
        for (Map.Entry<String, com.google.gson.JsonElement> entry : data.entrySet()) {
            System.out.println(entry.getKey() + ": " + entry.getValue().getClass().getSimpleName() + " - Example: " + entry.getValue().toString().substring(0, Math.min(100, entry.getValue().toString().length())) + "...");
        }
    }

    public void write(JsonObject newData) throws IOException {
        if (newData != null) {
            this.data = newData;
        }
        if (this.data == null) {
            throw new IllegalStateException("No data to write.");
        }
        try (FileWriter writer = new FileWriter(filepath)) {
            new Gson().toJson(this.data, writer);
        }
        System.out.println("File written to " + filepath);
    }

    // Example usage:
    // public static void main(String[] args) throws IOException {
    //     IQBlocksHandler handler = new IQBlocksHandler("example.iqblocks");
    //     handler.read();
    //     handler.printProperties();
    //     JsonObject newData = new JsonObject();
    //     newData.addProperty("meta", "new data");
    //     handler.write(newData);
    // }
}

6. Javascript class that can open any file of format .IQBLOCKS and decode read and write and print to console all the properties from the above list

const fs = require('fs'); // For Node.js

class IQBlocksHandler {
    constructor(filepath) {
        this.filepath = filepath;
        this.data = null;
    }

    read() {
        try {
            const fileContent = fs.readFileSync(this.filepath, 'utf8');
            this.data = JSON.parse(fileContent);
            return this.data;
        } catch (err) {
            console.error('Error reading file:', err.message);
        }
    }

    printProperties() {
        if (!this.data) {
            this.read();
        }
        console.log('Properties from .IQBLOCKS file:');
        for (const [key, value] of Object.entries(this.data)) {
            console.log(`${key}: ${typeof value} - Example: ${JSON.stringify(value).slice(0, 100)}...`);
        }
    }

    write(newData = null) {
        if (newData) {
            this.data = newData;
        }
        if (!this.data) {
            throw new Error('No data to write.');
        }
        fs.writeFileSync(this.filepath, JSON.stringify(this.data, null, 4));
        console.log(`File written to ${this.filepath}`);
    }
}

// Example usage:
// const handler = new IQBlocksHandler('example.iqblocks');
// handler.read();
// handler.printProperties();
// handler.write({ meta: { new: 'data' } });

7. C class that can open any file of format .IQBLOCKS and decode read and write and print to console all the properties from the above list

(Note: C does not have built-in JSON parsing, so this uses a simple string-based approach for demonstration. For real use, integrate a library like jansson or parson.)

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct {
    char *filepath;
    char *data; // Raw JSON string
} IQBlocksHandler;

IQBlocksHandler* createIQBlocksHandler(const char *filepath) {
    IQBlocksHandler *handler = malloc(sizeof(IQBlocksHandler));
    handler->filepath = strdup(filepath);
    handler->data = NULL;
    return handler;
}

void readIQBlocks(IQBlocksHandler *handler) {
    FILE *fp = fopen(handler->filepath, "r");
    if (fp == NULL) {
        perror("File not found");
        return;
    }
    fseek(fp, 0, SEEK_END);
    long size = ftell(fp);
    fseek(fp, 0, SEEK_SET);
    handler->data = malloc(size + 1);
    fread(handler->data, 1, size, fp);
    handler->data[size] = '\0';
    fclose(fp);
}

void printProperties(IQBlocksHandler *handler) {
    if (handler->data == NULL) {
        readIQBlocks(handler);
    }
    printf("Properties from .IQBLOCKS file (simplified parse):\n");
    // Simple parse: find top-level keys (assumes well-formed JSON)
    char *ptr = handler->data;
    while ((ptr = strstr(ptr, "\"")) != NULL) {
        ptr++; // Skip opening quote
        char *end = strstr(ptr, "\"");
        if (end) {
            *end = '\0';
            printf("%s: (value type and example truncated)\n", ptr);
            ptr = end + 1;
            // Skip to value, but for simplicity, just print keys
        } else {
            break;
        }
    }
}

void writeIQBlocks(IQBlocksHandler *handler, const char *newData) {
    FILE *fp = fopen(handler->filepath, "w");
    if (fp == NULL) {
        perror("Cannot write file");
        return;
    }
    fprintf(fp, "%s", newData ? newData : handler->data);
    fclose(fp);
    printf("File written to %s\n", handler->filepath);
}

void destroyIQBlocksHandler(IQBlocksHandler *handler) {
    free(handler->filepath);
    free(handler->data);
    free(handler);
}

// Example usage:
// int main() {
//     IQBlocksHandler *handler = createIQBlocksHandler("example.iqblocks");
//     readIQBlocks(handler);
//     printProperties(handler);
//     writeIQBlocks(handler, "{\"meta\": \"new data\"}");
//     destroyIQBlocksHandler(handler);
//     return 0;
// }