Task 026: .AML File Format

Task 026: .AML File Format

The .AML file extension is associated with multiple formats, primarily ACPI Machine Language (AML) for system hardware configuration, Automation Markup Language (AutomationML) for plant engineering, and Microsoft Assistance Markup Language (MAML) for help documentation. Since the task does not specify which .AML format to focus on and the ACPI Machine Language is the most commonly referenced in system-level programming contexts, I will assume the task refers to ACPI Machine Language (.AML) files, which are used to configure hardware properties in the Advanced Configuration and Power Interface (ACPI) specification. If you intended a different .AML format (e.g., AutomationML or MAML), please clarify, and I can tailor the response accordingly.

Step 1: Properties of the ACPI Machine Language (.AML) File Format

ACPI .AML files are binary files containing machine-readable byte code that defines hardware configurations and power management instructions for ACPI-compatible systems. Based on the provided references and the ACPI specification, the intrinsic properties of the .AML file format relevant to its file system are:

  1. File Extension: .aml
  2. File Type: Binary file containing ACPI Machine Language (AML) byte code.
  3. Structure: Comprises Differentiated System Description Table (DSDT) and Secondary System Description Table (SSDT) tables, which define devices and objects in the ACPI namespace.
  4. Encoding: Machine-independent byte code, parsed by the ACPI AML interpreter.
  5. Purpose: Stores instructions for configuring hardware settings, such as power management and device properties, used by the operating system.
  6. Namespace: Defines a hierarchical ACPI namespace containing device and object definitions.
  7. Compilation: Typically compiled from ACPI Source Language (ASL) files (.asl or .dsl) using an ASL compiler like iasl.
  8. File Location: Often placed in the root directory (e.g., on Mac OS X for Hackintosh systems) or specific system directories (e.g., /sys/firmware/acpi/tables on Linux).
  9. Access Method: Read and parsed by the operating system’s ACPI interpreter; not directly editable (must be decompiled to .dsl for editing).
  10. Versioning: Conforms to ACPI specification versions (e.g., ACPI 6.4 as of the latest reference), ensuring backward compatibility.
  11. Size: Variable, depending on the complexity of the DSDT and SSDT tables, typically ranging from a few KB to tens of KB.
  12. Integrity: Must be valid AML byte code to be parsed correctly by the ACPI interpreter; errors can cause system boot or configuration issues.

These properties are derived from the ACPI specification and related sources, focusing on aspects intrinsic to the file system and its role in hardware configuration.

Challenges and Assumptions

  • Ambiguity of .AML: The .AML extension has multiple uses (ACPI, AutomationML, MAML). I’m focusing on ACPI AML due to its prominence in system programming.
  • Parsing Complexity: AML is a low-level, binary format that requires an AML interpreter or decompiler (e.g., iasl) to read meaningfully. Direct parsing in Python, Java, JavaScript, or C is complex and typically not done without specialized libraries.
  • Implementation: Since AML files are binary and require an interpreter, the classes below will simulate basic file operations (open, read, write) and focus on extracting and displaying metadata or properties where possible. Full AML parsing requires tools like the ACPICA library (iasl), which is beyond the scope of a simple class implementation. Instead, the classes will:
  • Open and read the file as binary data.
  • Attempt to identify basic properties (e.g., file size, signature).
  • Print the listed properties.
  • Write a simple AML file (e.g., a minimal valid AML structure).
  • C Class: C does not have "classes" in the object-oriented sense, so I will provide a C implementation using structs and functions to mimic class-like behavior.

Step 2: Python Class for AML File Handling

import os
import struct

class AMLFileHandler:
    def __init__(self, file_path):
        self.file_path = file_path
        self.properties = {
            "file_extension": ".aml",
            "file_type": "Binary ACPI Machine Language",
            "structure": "Contains DSDT and SSDT tables",
            "encoding": "Machine-independent byte code",
            "purpose": "Hardware configuration and power management",
            "namespace": "Hierarchical ACPI namespace",
            "compilation": "Compiled from ASL (.asl/.dsl) files",
            "file_location": "Root or /sys/firmware/acpi/tables",
            "access_method": "Parsed by ACPI interpreter",
            "versioning": "ACPI spec (e.g., 6.4)",
            "size": None,  # To be determined
            "integrity": "Must be valid AML byte code"
        }

    def open_and_read(self):
        """Open and read the AML file, extract basic properties."""
        try:
            with open(self.file_path, 'rb') as f:
                data = f.read()
                self.properties["size"] = len(data)
                # Check for DSDT signature (first 4 bytes)
                if len(data) >= 4 and data[:4] == b'DSDT':
                    self.properties["structure"] = "Valid DSDT table detected"
                print("AML file opened successfully.")
                self.print_properties()
        except FileNotFoundError:
            print(f"Error: File {self.file_path} not found.")
        except Exception as e:
            print(f"Error reading AML file: {e}")

    def write(self, output_path):
        """Write a minimal AML file (example DSDT header)."""
        try:
            # Minimal DSDT header (36 bytes, simplified)
            dsdt_header = struct.pack(
                '<4sIBB6s8sI4sI4sII',  # Format: signature, length, revision, checksum, etc.
                b'DSDT',  # Signature
                36,       # Length (minimal)
                1,        # Revision
                0,        # Checksum (placeholder)
                b'OEMID ', # OEM ID
                b'TABLEID',# Table ID
                0x00000001,# OEM Revision
                b'INTL',   # Creator ID
                0x00000001,# Creator Revision
                0,        # Reserved
                0         # Reserved
            )
            with open(output_path, 'wb') as f:
                f.write(dsdt_header)
            print(f"Minimal AML file written to {output_path}.")
        except Exception as e:
            print(f"Error writing AML file: {e}")

    def print_properties(self):
        """Print all AML file properties."""
        print("\nAML File Properties:")
        for key, value in self.properties.items():
            print(f"{key}: {value}")

# Example usage
if __name__ == "__main__":
    aml_handler = AMLFileHandler("test.aml")
    aml_handler.open_and_read()
    aml_handler.write("output.aml")

Explanation:

  • Properties: The class initializes with a dictionary of AML properties based on the ACPI specification.
  • Open and Read: Opens the file in binary mode, reads its size, and checks for a DSDT signature (first 4 bytes). Full AML parsing requires an external tool like iasl.
  • Write: Creates a minimal AML file with a DSDT header (simplified for demonstration, as real AML requires complex byte code).
  • Print: Outputs all properties to the console.

Step 3: Java Class for AML File Handling

import java.io.*;
import java.util.HashMap;
import java.util.Map;

public class AMLFileHandler {
    private String filePath;
    private Map<String, String> properties;

    public AMLFileHandler(String filePath) {
        this.filePath = filePath;
        this.properties = new HashMap<>();
        initializeProperties();
    }

    private void initializeProperties() {
        properties.put("file_extension", ".aml");
        properties.put("file_type", "Binary ACPI Machine Language");
        properties.put("structure", "Contains DSDT and SSDT tables");
        properties.put("encoding", "Machine-independent byte code");
        properties.put("purpose", "Hardware configuration and power management");
        properties.put("namespace", "Hierarchical ACPI namespace");
        properties.put("compilation", "Compiled from ASL (.asl/.dsl) files");
        properties.put("file_location", "Root or /sys/firmware/acpi/tables");
        properties.put("access_method", "Parsed by ACPI interpreter");
        properties.put("versioning", "ACPI spec (e.g., 6.4)");
        properties.put("size", "Unknown");
        properties.put("integrity", "Must be valid AML byte code");
    }

    public void openAndRead() {
        try (FileInputStream fis = new FileInputStream(filePath)) {
            byte[] data = fis.readAllBytes();
            properties.put("size", String.valueOf(data.length));
            // Check for DSDT signature
            if (data.length >= 4 && new String(data, 0, 4).equals("DSDT")) {
                properties.put("structure", "Valid DSDT table detected");
            }
            System.out.println("AML file opened successfully.");
            printProperties();
        } catch (FileNotFoundException e) {
            System.out.println("Error: File " + filePath + " not found.");
        } catch (IOException e) {
            System.out.println("Error reading AML file: " + e.getMessage());
        }
    }

    public void write(String outputPath) {
        try (FileOutputStream fos = new FileOutputStream(outputPath)) {
            // Minimal DSDT header (36 bytes, simplified)
            byte[] dsdtHeader = new byte[36];
            System.arraycopy("DSDT".getBytes(), 0, dsdtHeader, 0, 4); // Signature
            dsdtHeader[4] = 36; // Length (low byte)
            dsdtHeader[9] = 1;  // Revision
            System.arraycopy("OEMID ".getBytes(), 0, dsdtHeader, 10, 6); // OEM ID
            System.arraycopy("TABLEID".getBytes(), 0, dsdtHeader, 16, 8); // Table ID
            System.arraycopy("INTL".getBytes(), 0, dsdtHeader, 28, 4); // Creator ID
            fos.write(dsdtHeader);
            System.out.println("Minimal AML file written to " + outputPath);
        } catch (IOException e) {
            System.out.println("Error writing AML file: " + e.getMessage());
        }
    }

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

    public static void main(String[] args) {
        AMLFileHandler handler = new AMLFileHandler("test.aml");
        handler.openAndRead();
        handler.write("output.aml");
    }
}

Explanation:

  • Properties: Stored in a HashMap initialized with AML properties.
  • Open and Read: Reads the file as a byte array, extracts size, and checks for the DSDT signature.
  • Write: Writes a minimal AML file with a DSDT header.
  • Print: Displays all properties to the console.

Step 4: JavaScript Class for AML File Handling

const fs = require('fs').promises;

class AMLFileHandler {
    constructor(filePath) {
        this.filePath = filePath;
        this.properties = {
            file_extension: '.aml',
            file_type: 'Binary ACPI Machine Language',
            structure: 'Contains DSDT and SSDT tables',
            encoding: 'Machine-independent byte code',
            purpose: 'Hardware configuration and power management',
            namespace: 'Hierarchical ACPI namespace',
            compilation: 'Compiled from ASL (.asl/.dsl) files',
            file_location: 'Root or /sys/firmware/acpi/tables',
            access_method: 'Parsed by ACPI interpreter',
            versioning: 'ACPI spec (e.g., 6.4)',
            size: null,
            integrity: 'Must be valid AML byte code'
        };
    }

    async openAndRead() {
        try {
            const data = await fs.readFile(this.filePath);
            this.properties.size = data.length;
            // Check for DSDT signature
            if (data.length >= 4 && data.slice(0, 4).toString() === 'DSDT') {
                this.properties.structure = 'Valid DSDT table detected';
            }
            console.log('AML file opened successfully.');
            this.printProperties();
        } catch (error) {
            if (error.code === 'ENOENT') {
                console.log(`Error: File ${this.filePath} not found.`);
            } else {
                console.log(`Error reading AML file: ${error.message}`);
            }
        }
    }

    async write(outputPath) {
        try {
            // Minimal DSDT header (36 bytes, simplified)
            const dsdtHeader = Buffer.alloc(36);
            dsdtHeader.write('DSDT', 0); // Signature
            dsdtHeader.writeUInt32LE(36, 4); // Length
            dsdtHeader.writeUInt8(1, 9); // Revision
            dsdtHeader.write('OEMID ', 10); // OEM ID
            dsdtHeader.write('TABLEID', 16); // Table ID
            dsdtHeader.write('INTL', 28); // Creator ID
            await fs.writeFile(outputPath, dsdtHeader);
            console.log(`Minimal AML file written to ${outputPath}`);
        } catch (error) {
            console.log(`Error writing AML file: ${error.message}`);
        }
    }

    printProperties() {
        console.log('\nAML File Properties:');
        for (const [key, value] of Object.entries(this.properties)) {
            console.log(`${key}: ${value}`);
        }
    }
}

// Example usage
(async () => {
    const handler = new AMLFileHandler('test.aml');
    await handler.openAndRead();
    await handler.write('output.aml');
})();

Explanation:

  • Properties: Stored as an object with AML properties.
  • Open and Read: Uses Node.js fs module to read the file, checks size and DSDT signature.
  • Write: Writes a minimal AML file with a DSDT header.
  • Print: Logs properties to the console.

Step 5: C Implementation for AML File Handling

Since C does not support classes, I’ll use a struct and functions to achieve similar functionality.

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

typedef struct {
    char* file_path;
    struct {
        char* file_extension;
        char* file_type;
        char* structure;
        char* encoding;
        char* purpose;
        char* namespace;
        char* compilation;
        char* file_location;
        char* access_method;
        char* versioning;
        long size;
        char* integrity;
    } properties;
} AMLFileHandler;

void init_aml_handler(AMLFileHandler* handler, const char* file_path) {
    handler->file_path = strdup(file_path);
    handler->properties.file_extension = ".aml";
    handler->properties.file_type = "Binary ACPI Machine Language";
    handler->properties.structure = "Contains DSDT and SSDT tables";
    handler->properties.encoding = "Machine-independent byte code";
    handler->properties.purpose = "Hardware configuration and power management";
    handler->properties.namespace = "Hierarchical ACPI namespace";
    handler->properties.compilation = "Compiled from ASL (.asl/.dsl) files";
    handler->properties.file_location = "Root or /sys/firmware/acpi/tables";
    handler->properties.access_method = "Parsed by ACPI interpreter";
    handler->properties.versioning = "ACPI spec (e.g., 6.4)";
    handler->properties.size = 0;
    handler->properties.integrity = "Must be valid AML byte code";
}

void open_and_read(AMLFileHandler* handler) {
    FILE* file = fopen(handler->file_path, "rb");
    if (!file) {
        printf("Error: File %s not found.\n", handler->file_path);
        return;
    }

    fseek(file, 0, SEEK_END);
    handler->properties.size = ftell(file);
    fseek(file, 0, SEEK_SET);

    char signature[5] = {0};
    if (fread(signature, 1, 4, file) == 4 && strcmp(signature, "DSDT") == 0) {
        handler->properties.structure = "Valid DSDT table detected";
    }

    printf("AML file opened successfully.\n");
    fclose(file);
    print_properties(handler);
}

void write_aml(AMLFileHandler* handler, const char* output_path) {
    FILE* file = fopen(output_path, "wb");
    if (!file) {
        printf("Error: Could not create file %s.\n", output_path);
        return;
    }

    // Minimal DSDT header (36 bytes, simplified)
    unsigned char dsdt_header[36] = {0};
    memcpy(dsdt_header, "DSDT", 4); // Signature
    dsdt_header[4] = 36; // Length (low byte)
    dsdt_header[9] = 1;  // Revision
    memcpy(dsdt_header + 10, "OEMID ", 6); // OEM ID
    memcpy(dsdt_header + 16, "TABLEID", 8); // Table ID
    memcpy(dsdt_header + 28, "INTL", 4); // Creator ID

    fwrite(dsdt_header, 1, 36, file);
    fclose(file);
    printf("Minimal AML file written to %s\n", output_path);
}

void print_properties(AMLFileHandler* handler) {
    printf("\nAML File Properties:\n");
    printf("file_extension: %s\n", handler->properties.file_extension);
    printf("file_type: %s\n", handler->properties.file_type);
    printf("structure: %s\n", handler->properties.structure);
    printf("encoding: %s\n", handler->properties.encoding);
    printf("purpose: %s\n", handler->properties.purpose);
    printf("namespace: %s\n", handler->properties.namespace);
    printf("compilation: %s\n", handler->properties.compilation);
    printf("file_location: %s\n", handler->properties.file_location);
    printf("access_method: %s\n", handler->properties.access_method);
    printf("versioning: %s\n", handler->properties.versioning);
    printf("size: %ld bytes\n", handler->properties.size);
    printf("integrity: %s\n", handler->properties.integrity);
}

void free_aml_handler(AMLFileHandler* handler) {
    free(handler->file_path);
}

int main() {
    AMLFileHandler handler;
    init_aml_handler(&handler, "test.aml");
    open_and_read(&handler);
    write_aml(&handler, "output.aml");
    free_aml_handler(&handler);
    return 0;
}

Explanation:

  • Properties: Stored in a struct with string fields and a size field.
  • Open and Read: Opens the file in binary mode, reads size, and checks for the DSDT signature.
  • Write: Writes a minimal AML file with a DSDT header.
  • Print: Prints all properties to the console.
  • Memory Management: Includes a function to free allocated memory.

Notes

  • Limitations: Full AML parsing requires an AML interpreter or decompiler (e.g., iasl from ACPICA). The provided classes focus on basic file operations and metadata extraction due to the complexity of AML byte code.
  • Testing: The code assumes the existence of a test.aml file for reading. For testing, you can use an existing AML file or create one using an ASL compiler.
  • Alternative AML Formats: If you meant AutomationML (XML-based) or MAML, I can provide classes tailored to those formats, which are simpler to parse due to their XML structure.
  • Dependencies: The JavaScript implementation requires Node.js for file system access. The Python and Java implementations use standard libraries. The C implementation is standalone.

If you need clarification, a different .AML format, or additional functionality (e.g., full AML parsing with ACPICA), please let me know!

  1. Properties of .AML file format:
  • Signature: 4-byte ASCII string
  • Length: 4-byte unsigned int
  • Revision: 1-byte unsigned int
  • Checksum: 1-byte unsigned int
  • OEMID: 6-byte ASCII string
  • OEM Table ID: 8-byte ASCII string
  • OEM Revision: 4-byte unsigned int
  • Creator ID: 4-byte ASCII string
  • Creator Revision: 4-byte unsigned int
  • AML Bytecode: (Length - 36) bytes
  1. Python class:
import struct

class AMLFile:
    def __init__(self, filename):
        with open(filename, 'rb') as f:
            data = f.read()
        fmt = '<4sIBB6s8sI4sI'
        self.signature, self.length, self.revision, self.checksum, self.oemid, \
        self.oem_table_id, self.oem_revision, self.creator_id, self.creator_revision = struct.unpack(fmt, data[:36])
        self.aml = data[36:self.length]
    
    def read_properties(self):
        return {
            'signature': self.signature.decode(),
            'length': self.length,
            'revision': self.revision,
            'checksum': self.checksum,
            'oemid': self.oemid.decode(),
            'oem_table_id': self.oem_table_id.decode(),
            'oem_revision': self.oem_revision,
            'creator_id': self.creator_id.decode(),
            'creator_revision': self.creator_revision,
            'aml': self.aml
        }
    
    def write(self, filename):
        fmt = '<4sIBB6s8sI4sI'
        header = struct.pack(fmt, self.signature, self.length, self.revision, 0,
                             self.oemid, self.oem_table_id, self.oem_revision,
                             self.creator_id, self.creator_revision)
        data = header + self.aml
        checksum = (256 - (sum(data) % 256)) % 256
        data = data[:9] + bytes([checksum]) + data[10:]
        with open(filename, 'wb') as f:
            f.write(data)
  1. Java class:
import java.io.*;
import java.nio.*;
import java.nio.channels.FileChannel;

public class AMLFile {
    private String signature;
    private int length;
    private byte revision;
    private byte checksum;
    private String oemid;
    private String oemTableId;
    private int oemRevision;
    private String creatorId;
    private int creatorRevision;
    private byte[] aml;

    public AMLFile(String filename) throws IOException {
        RandomAccessFile raf = new RandomAccessFile(filename, "r");
        FileChannel fc = raf.getChannel();
        ByteBuffer bb = ByteBuffer.allocate((int) raf.length()).order(ByteOrder.LITTLE_ENDIAN);
        fc.read(bb);
        bb.flip();
        byte[] sigBytes = new byte[4];
        bb.get(sigBytes);
        signature = new String(sigBytes);
        length = bb.getInt();
        revision = bb.get();
        checksum = bb.get();
        byte[] oemBytes = new byte[6];
        bb.get(oemBytes);
        oemid = new String(oemBytes);
        byte[] tableBytes = new byte[8];
        bb.get(tableBytes);
        oemTableId = new String(tableBytes);
        oemRevision = bb.getInt();
        byte[] creatorBytes = new byte[4];
        bb.get(creatorBytes);
        creatorId = new String(creatorBytes);
        creatorRevision = bb.getInt();
        aml = new byte[length - 36];
        bb.get(aml);
        raf.close();
    }

    public void readProperties() {
        System.out.println("Signature: " + signature);
        System.out.println("Length: " + length);
        System.out.println("Revision: " + revision);
        System.out.println("Checksum: " + checksum);
        System.out.println("OEMID: " + oemid);
        System.out.println("OEM Table ID: " + oemTableId);
        System.out.println("OEM Revision: " + oemRevision);
        System.out.println("Creator ID: " + creatorId);
        System.out.println("Creator Revision: " + creatorRevision);
        // AML as byte array, not printed
    }

    public void write(String filename) throws IOException {
        ByteBuffer bb = ByteBuffer.allocate(length).order(ByteOrder.LITTLE_ENDIAN);
        bb.put(signature.getBytes());
        bb.putInt(length);
        bb.put(revision);
        bb.put((byte) 0); // temp checksum
        bb.put(oemid.getBytes());
        bb.put(oemTableId.getBytes());
        bb.putInt(oemRevision);
        bb.put(creatorId.getBytes());
        bb.putInt(creatorRevision);
        bb.put(aml);
        bb.flip();
        byte[] data = new byte[length];
        bb.get(data);
        int sum = 0;
        for (byte b : data) sum += b & 0xFF;
        byte newChecksum = (byte) ((256 - (sum % 256)) % 256);
        data[9] = newChecksum;
        try (FileOutputStream fos = new FileOutputStream(filename)) {
            fos.write(data);
        }
    }
}
  1. JavaScript class:
const fs = require('fs');

class AMLFile {
    constructor(filename) {
        const data = fs.readFileSync(filename);
        const dv = new DataView(data.buffer);
        this.signature = String.fromCharCode(...data.slice(0,4));
        this.length = dv.getUint32(4, true);
        this.revision = data[8];
        this.checksum = data[9];
        this.oemid = String.fromCharCode(...data.slice(10,16));
        this.oemTableId = String.fromCharCode(...data.slice(16,24));
        this.oemRevision = dv.getUint32(24, true);
        this.creatorId = String.fromCharCode(...data.slice(28,32));
        this.creatorRevision = dv.getUint32(32, true);
        this.aml = data.slice(36, this.length);
    }

    readProperties() {
        return {
            signature: this.signature,
            length: this.length,
            revision: this.revision,
            checksum: this.checksum,
            oemid: this.oemid,
            oemTableId: this.oemTableId,
            oemRevision: this.oemRevision,
            creatorId: this.creatorId,
            creatorRevision: this.creatorRevision,
            aml: this.aml
        };
    }

    write(filename) {
        const buffer = Buffer.alloc(this.length);
        buffer.write(this.signature, 0, 4);
        buffer.writeUInt32LE(this.length, 4);
        buffer[8] = this.revision;
        buffer[9] = 0; // temp
        buffer.write(this.oemid, 10, 6);
        buffer.write(this.oemTableId, 16, 8);
        buffer.writeUInt32LE(this.oemRevision, 24);
        buffer.write(this.creatorId, 28, 4);
        buffer.writeUInt32LE(this.creatorRevision, 32);
        this.aml.copy(buffer, 36);
        let sum = 0;
        for (let b of buffer) sum += b;
        buffer[9] = (256 - (sum % 256)) % 256;
        fs.writeFileSync(filename, buffer);
    }
}
  1. C struct and functions:
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>

typedef struct {
    char signature[4];
    uint32_t length;
    uint8_t revision;
    uint8_t checksum;
    char oemid[6];
    char oem_table_id[8];
    uint32_t oem_revision;
    char creator_id[4];
    uint32_t creator_revision;
    uint8_t *aml;
} AMLFile;

AMLFile* aml_open(const char* filename) {
    FILE* f = fopen(filename, "rb");
    if (!f) return NULL;
    fseek(f, 0, SEEK_END);
    long size = ftell(f);
    fseek(f, 0, SEEK_SET);
    uint8_t* data = malloc(size);
    fread(data, 1, size, f);
    fclose(f);
    
    AMLFile* aml = malloc(sizeof(AMLFile));
    memcpy(aml->signature, data, 4);
    aml->length = *(uint32_t*)(data + 4);
    aml->revision = data[8];
    aml->checksum = data[9];
    memcpy(aml->oemid, data + 10, 6);
    memcpy(aml->oem_table_id, data + 16, 8);
    aml->oem_revision = *(uint32_t*)(data + 24);
    memcpy(aml->creator_id, data + 28, 4);
    aml->creator_revision = *(uint32_t*)(data + 32);
    aml->aml = malloc(aml->length - 36);
    memcpy(aml->aml, data + 36, aml->length - 36);
    free(data);
    return aml;
}

void aml_print_properties(AMLFile* aml) {
    printf("Signature: %.4s\n", aml->signature);
    printf("Length: %u\n", aml->length);
    printf("Revision: %u\n", aml->revision);
    printf("Checksum: %u\n", aml->checksum);
    printf("OEMID: %.6s\n", aml->oemid);
    printf("OEM Table ID: %.8s\n", aml->oem_table_id);
    printf("OEM Revision: %u\n", aml->oem_revision);
    printf("Creator ID: %.4s\n", aml->creator_id);
    printf("Creator Revision: %u\n", aml->creator_revision);
    // AML not printed
}

void aml_write(AMLFile* aml, const char* filename) {
    uint8_t* data = malloc(aml->length);
    memcpy(data, aml->signature, 4);
    *(uint32_t*)(data + 4) = aml->length;
    data[8] = aml->revision;
    data[9] = 0; // temp
    memcpy(data + 10, aml->oemid, 6);
    memcpy(data + 16, aml->oem_table_id, 8);
    *(uint32_t*)(data + 24) = aml->oem_revision;
    memcpy(data + 28, aml->creator_id, 4);
    *(uint32_t*)(data + 32) = aml->creator_revision;
    memcpy(data + 36, aml->aml, aml->length - 36);
    
    uint32_t sum = 0;
    for (uint32_t i = 0; i < aml->length; i++) sum += data[i];
    data[9] = (256 - (sum % 256)) % 256;
    
    FILE* f = fopen(filename, "wb");
    fwrite(data, 1, aml->length, f);
    fclose(f);
    free(data);
}

void aml_free(AMLFile* aml) {
    free(aml->aml);
    free(aml);
}