Task 023: .AIO File Format
Task 023: .AIO File Format
The .AIO file extension is associated with multiple file formats, primarily the APL Transfer Format File (used with the APL programming language) and, less commonly, as a compressed archive format related to 7-Zip or a bitmap image format. However, there is no standardized, publicly available specification for the .AIO file format that provides a clear structure or intrinsic file system properties. Based on available information, the APL Transfer Format File is described as a data file for transferring data in the APL programming language, developed by IBM in the 1960s, but it is considered obsolete with no detailed structural specification provided in the sources. Other uses, such as 7-Zip archives or bitmap formats, also lack specific structural details beyond general compression or image characteristics.
Given the lack of a concrete specification, I’ll assume a hypothetical .AIO file format for the purpose of this task, modeling it as a simple structured binary file with a header containing metadata (common in data transfer formats like APL). The assumed format will include a header with a magic number, version, file size, and a data section. This is a reasonable approximation for a transfer format, allowing the creation of classes to read, write, and display properties. If a specific .AIO format is intended, please provide additional details or a specification.
1. List of Properties Intrinsic to the .AIO File Format (Assumed)
Based on the hypothetical binary format:
- Magic Number: A fixed identifier (e.g., "AIOF") to verify the file type (4 bytes).
- Version: File format version (e.g., 1.0, stored as a float, 4 bytes).
- File Size: Total size of the file in bytes (4 bytes, unsigned integer).
- Data Length: Length of the data section in bytes (4 bytes, unsigned integer).
- Data: The actual content (variable length, assumed to be text for simplicity).
These properties are intrinsic to the file’s structure and can be accessed via file system operations (reading/writing binary data).
2. Python Class for .AIO File
import struct
class AIOFile:
def __init__(self, filename):
self.filename = filename
self.magic_number = b"AIOF"
self.version = 1.0
self.file_size = 0
self.data_length = 0
self.data = b""
def read(self):
try:
with open(self.filename, 'rb') as f:
# Read header (magic: 4s, version: f, file_size: I, data_length: I)
header = f.read(16)
if len(header) != 16:
raise ValueError("Invalid header size")
magic, version, file_size, data_length = struct.unpack('4sfII', header)
if magic != self.magic_number:
raise ValueError("Invalid magic number")
self.version = version
self.file_size = file_size
self.data_length = data_length
self.data = f.read(data_length).decode('utf-8')
except Exception as e:
print(f"Error reading file: {e}")
def write(self, data):
try:
self.data = data.encode('utf-8')
self.data_length = len(self.data)
self.file_size = 16 + self.data_length # Header + data
with open(self.filename, 'wb') as f:
f.write(struct.pack('4sfII', self.magic_number, self.version, self.file_size, self.data_length))
f.write(self.data)
except Exception as e:
print(f"Error writing file: {e}")
def print_properties(self):
print(f"Magic Number: {self.magic_number.decode('utf-8')}")
print(f"Version: {self.version}")
print(f"File Size: {self.file_size} bytes")
print(f"Data Length: {self.data_length} bytes")
print(f"Data: {self.data}")
# Example usage
if __name__ == "__main__":
aio = AIOFile("test.aio")
aio.write("Sample data")
aio.print_properties()
aio.read()
aio.print_properties()
3. Java Class for .AIO File
import java.io.*;
public class AIOFile {
private String filename;
private String magicNumber = "AIOF";
private float version = 1.0f;
private int fileSize = 0;
private int dataLength = 0;
private String data = "";
public AIOFile(String filename) {
this.filename = filename;
}
public void read() {
try (DataInputStream dis = new DataInputStream(new FileInputStream(filename))) {
byte[] magic = new byte[4];
dis.readFully(magic);
if (!new String(magic).equals(magicNumber)) {
throw new IOException("Invalid magic number");
}
version = dis.readFloat();
fileSize = dis.readInt();
dataLength = dis.readInt();
byte[] dataBytes = new byte[dataLength];
dis.readFully(dataBytes);
data = new String(dataBytes, "UTF-8");
} catch (IOException e) {
System.out.println("Error reading file: " + e.getMessage());
}
}
public void write(String data) {
this.data = data;
this.dataLength = data.getBytes().length;
this.fileSize = 16 + dataLength; // Header + data
try (DataOutputStream dos = new DataOutputStream(new FileOutputStream(filename))) {
dos.writeBytes(magicNumber);
dos.writeFloat(version);
dos.writeInt(fileSize);
dos.writeInt(dataLength);
dos.writeBytes(data);
} catch (IOException e) {
System.out.println("Error writing file: " + e.getMessage());
}
}
public void printProperties() {
System.out.println("Magic Number: " + magicNumber);
System.out.println("Version: " + version);
System.out.println("File Size: " + fileSize + " bytes");
System.out.println("Data Length: " + dataLength + " bytes");
System.out.println("Data: " + data);
}
public static void main(String[] args) {
AIOFile aio = new AIOFile("test.aio");
aio.write("Sample data");
aio.printProperties();
aio.read();
aio.printProperties();
}
}
4. JavaScript Class for .AIO File
const fs = require('fs');
class AIOFile {
constructor(filename) {
this.filename = filename;
this.magicNumber = "AIOF";
this.version = 1.0;
this.fileSize = 0;
this.dataLength = 0;
this.data = "";
}
read() {
try {
const buffer = fs.readFileSync(this.filename);
if (buffer.length < 16) throw new Error("Invalid header size");
const magic = buffer.toString('utf8', 0, 4);
if (magic !== this.magicNumber) throw new Error("Invalid magic number");
this.version = buffer.readFloatLE(4);
this.fileSize = buffer.readUInt32LE(8);
this.dataLength = buffer.readUInt32LE(12);
this.data = buffer.toString('utf8', 16, 16 + this.dataLength);
} catch (e) {
console.log(`Error reading file: ${e.message}`);
}
}
write(data) {
try {
this.data = data;
this.dataLength = Buffer.from(data).length;
this.fileSize = 16 + this.dataLength;
const buffer = Buffer.alloc(16 + this.dataLength);
buffer.write(this.magicNumber, 0, 4, 'utf8');
buffer.writeFloatLE(this.version, 4);
buffer.writeUInt32LE(this.fileSize, 8);
buffer.writeUInt32LE(this.dataLength, 12);
buffer.write(data, 16, 'utf8');
fs.writeFileSync(this.filename, buffer);
} catch (e) {
console.log(`Error writing file: ${e.message}`);
}
}
printProperties() {
console.log(`Magic Number: ${this.magicNumber}`);
console.log(`Version: ${this.version}`);
console.log(`File Size: ${this.fileSize} bytes`);
console.log(`Data Length: ${this.dataLength} bytes`);
console.log(`Data: ${this.data}`);
}
}
// Example usage
const aio = new AIOFile("test.aio");
aio.write("Sample data");
aio.printProperties();
aio.read();
aio.printProperties();
5. C Code for .AIO File
Note: C does not have classes, so this is implemented as a struct with functions.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
char magicNumber[5];
float version;
unsigned int fileSize;
unsigned int dataLength;
char* data;
} AIOFile;
void initAIOFile(AIOFile* aio, const char* filename) {
strncpy(aio->magicNumber, "AIOF", 5);
aio->version = 1.0f;
aio->fileSize = 0;
aio->dataLength = 0;
aio->data = NULL;
}
void readAIOFile(AIOFile* aio, const char* filename) {
FILE* file = fopen(filename, "rb");
if (!file) {
printf("Error opening file for reading\n");
return;
}
char magic[4];
if (fread(magic, 1, 4, file) != 4 || strncmp(magic, "AIOF", 4) != 0) {
printf("Invalid magic number\n");
fclose(file);
return;
}
if (fread(&aio->version, sizeof(float), 1, file) != 1 ||
fread(&aio->fileSize, sizeof(unsigned int), 1, file) != 1 ||
fread(&aio->dataLength, sizeof(unsigned int), 1, file) != 1) {
printf("Error reading header\n");
fclose(file);
return;
}
aio->data = (char*)malloc(aio->dataLength + 1);
if (fread(aio->data, 1, aio->dataLength, file) != aio->dataLength) {
printf("Error reading data\n");
free(aio->data);
aio->data = NULL;
fclose(file);
return;
}
aio->data[aio->dataLength] = '\0';
fclose(file);
}
void writeAIOFile(AIOFile* aio, const char* filename, const char* data) {
aio->dataLength = strlen(data);
aio->fileSize = 16 + aio->dataLength;
aio->data = (char*)malloc(aio->dataLength + 1);
strcpy(aio->data, data);
FILE* file = fopen(filename, "wb");
if (!file) {
printf("Error opening file for writing\n");
return;
}
fwrite(aio->magicNumber, 1, 4, file);
fwrite(&aio->version, sizeof(float), 1, file);
fwrite(&aio->fileSize, sizeof(unsigned int), 1, file);
fwrite(&aio->dataLength, sizeof(unsigned int), 1, file);
fwrite(aio->data, 1, aio->dataLength, file);
fclose(file);
}
void printProperties(AIOFile* aio) {
printf("Magic Number: %s\n", aio->magicNumber);
printf("Version: %.1f\n", aio->version);
printf("File Size: %u bytes\n", aio->fileSize);
printf("Data Length: %u bytes\n", aio->dataLength);
printf("Data: %s\n", aio->data ? aio->data : "None");
}
void freeAIOFile(AIOFile* aio) {
if (aio->data) free(aio->data);
}
int main() {
AIOFile aio;
initAIOFile(&aio, "test.aio");
writeAIOFile(&aio, "test.aio", "Sample data");
printProperties(&aio);
freeAIOFile(&aio);
initAIOFile(&aio, "test.aio");
readAIOFile(&aio, "test.aio");
printProperties(&aio);
freeAIOFile(&aio);
return 0;
}
Notes
- Assumptions: Due to the lack of a detailed .AIO specification, the format is assumed to be a simple binary structure with a header and data section. If the .AIO file is intended to be a 7-Zip archive or bitmap, the implementation would differ (e.g., using compression libraries or image processing).
- Error Handling: Each class includes basic error handling for invalid files or I/O issues.
- APL Context: If the .AIO file is specifically an APL Transfer Format File, it may require IBM APL software, which is obsolete, and no public specification exists for its structure.
- Limitations: The code assumes text data for simplicity. For real-world .AIO files, additional details about the data structure (e.g., APL-specific objects) would be needed.
- Testing: The example usage in each class writes a sample file and reads it back to demonstrate functionality.
If you have a specific .AIO file or a detailed specification, please provide it, and I can tailor the implementation accordingly.
1. List of all the properties of this file format intrinsic to its file system
Based on the specifications of the .AIO file format from IBM Personal Computer APL, it is a text-based format used for transferring APL workspaces. The file consists of one or more lines, where each line represents a single object (variable or function) in transfer form. There is no file-level header, footer, or metadata (e.g., no version, timestamp, or object count). Objects are separated by newlines, and the format is platform-agnostic for portability.
The intrinsic properties (fields) for each object in the format are:
- Object Type: A single character indicating the type ('N' for numeric arrays, 'C' for character arrays, 'F' for functions). This is the first character of each line.
- Object Name: A string immediately following the type (no space between type and name), representing the name of the variable or function. Names do not contain spaces.
- Rank: An integer (0-63) following the name (separated by a space), indicating the rank (number of dimensions) of the array or matrix representation.
- Dimensions: A list of rank integers (space-separated), specifying the shape of the array (e.g., rows and columns for a matrix). For scalars (rank 0), there are no dimensions. The product of dimensions determines the expected length of the data.
- Data: The content of the object, starting after a space following the last dimension:
- For 'N' (numeric): Space-separated numeric values (integers as whole numbers, reals with decimal or exponential notation, booleans as 0/1). The count of values must equal the product of dimensions.
- For 'C' (character) or 'F' (function): A raw string of characters (including spaces, preserved as-is), with length exactly equal to the product of dimensions. For functions, this is the flattened canonical representation (character matrix of the function definition, with rows padded to uniform length using spaces if needed).
These properties are intrinsic as they define the core structure and parsing rules of the format, ensuring compatibility for transfer across systems.
2. Python class
import functools
import operator
class AIOFile:
def __init__(self):
self.objects = [] # List of dicts: {'type': str, 'name': str, 'rank': int, 'dims': list[int], 'data': list[float] or str}
def open(self, filename, mode='r'):
if mode == 'r':
with open(filename, 'r') as f:
lines = f.readlines()
self.objects = []
for line in lines:
line = line.strip()
if not line:
continue
obj = self._parse_line(line)
self.objects.append(obj)
elif mode == 'w':
self.objects = []
else:
raise ValueError("Mode must be 'r' or 'w'")
def read(self):
return self.objects
def write(self, objects):
self.objects = objects
def save(self, filename):
with open(filename, 'w') as f:
for obj in self.objects:
f.write(self._serialize_object(obj) + '\n')
def _parse_line(self, line):
i = 0
obj_type = line[i]
i += 1
start = i
while i < len(line) and line[i] != ' ':
i += 1
name = line[start:i]
if line[i] != ' ':
raise ValueError("Invalid format: no space after name")
i += 1
start = i
while i < len(line) and line[i] != ' ':
i += 1
rank = int(line[start:i])
if line[i] != ' ':
raise ValueError("Invalid format: no space after rank")
i += 1
dims = []
for _ in range(rank):
start = i
while i < len(line) and line[i] != ' ':
i += 1
dims.append(int(line[start:i]))
if i >= len(line) or line[i] != ' ':
raise ValueError("Invalid format: missing space after dim")
i += 1
data_str = line[i:]
prod = functools.reduce(operator.mul, dims, 1) if dims else 1
if obj_type == 'N':
values_str = data_str.split()
if len(values_str) != prod:
raise ValueError(f"Data length mismatch: expected {prod}, got {len(values_str)}")
data = [float(v) if '.' in v or 'E' in v.upper() else int(v) for v in values_str]
elif obj_type in ['C', 'F']:
if len(data_str) != prod:
raise ValueError(f"Data length mismatch: expected {prod}, got {len(data_str)}")
data = data_str
else:
raise ValueError("Unknown type")
return {'type': obj_type, 'name': name, 'rank': rank, 'dims': dims, 'data': data}
def _serialize_object(self, obj):
parts = [obj['type'] + obj['name'], str(obj['rank'])]
parts.extend(str(d) for d in obj['dims'])
if obj['type'] == 'N':
data_part = ' '.join(str(v) for v in obj['data'])
else:
data_part = obj['data']
return ' '.join(parts) + ' ' + data_part
3. Java class
import java.io.*;
import java.util.*;
import java.util.stream.*;
public class AIOFile {
private List<Map<String, Object>> objects = new ArrayList<>(); // Each map: type:String, name:String, rank:Integer, dims:List<Integer>, data:List<Number> or String
public void open(String filename, String mode) throws IOException {
if (mode.equals("r")) {
objects.clear();
try (BufferedReader reader = new BufferedReader(new FileReader(filename))) {
String line;
while ((line = reader.readLine()) != null) {
line = line.trim();
if (!line.isEmpty()) {
Map<String, Object> obj = parseLine(line);
objects.add(obj);
}
}
}
} else if (mode.equals("w")) {
objects.clear();
} else {
throw new IllegalArgumentException("Mode must be 'r' or 'w'");
}
}
public List<Map<String, Object>> read() {
return new ArrayList<>(objects);
}
public void write(List<Map<String, Object>> newObjects) {
objects = new ArrayList<>(newObjects);
}
public void save(String filename) throws IOException {
try (BufferedWriter writer = new BufferedWriter(new FileWriter(filename))) {
for (Map<String, Object> obj : objects) {
writer.write(serializeObject(obj));
writer.newLine();
}
}
}
private Map<String, Object> parseLine(String line) {
int i = 0;
char type = line.charAt(i);
i++;
int start = i;
while (i < line.length() && line.charAt(i) != ' ') i++;
String name = line.substring(start, i);
if (i >= line.length() || line.charAt(i) != ' ') throw new IllegalArgumentException("Invalid format");
i++;
start = i;
while (i < line.length() && line.charAt(i) != ' ') i++;
int rank = Integer.parseInt(line.substring(start, i));
if (i >= line.length() || line.charAt(i) != ' ') throw new IllegalArgumentException("Invalid format");
i++;
List<Integer> dims = new ArrayList<>();
for (int d = 0; d < rank; d++) {
start = i;
while (i < line.length() && line.charAt(i) != ' ') i++;
dims.add(Integer.parseInt(line.substring(start, i)));
if (i >= line.length() || line.charAt(i) != ' ') throw new IllegalArgumentException("Invalid format");
i++;
}
String dataStr = line.substring(i);
long prod = dims.stream().mapToLong(Integer::longValue).reduce(1L, (a, b) -> a * b);
Object data;
if (type == 'N') {
String[] valuesStr = dataStr.split("\\s+");
if (valuesStr.length != prod) throw new IllegalArgumentException("Data length mismatch");
data = Arrays.stream(valuesStr).map(v -> v.contains(".") || v.toUpperCase().contains("E") ? Double.parseDouble(v) : Integer.parseInt(v)).collect(Collectors.toList());
} else if (type == 'C' || type == 'F') {
if (dataStr.length() != prod) throw new IllegalArgumentException("Data length mismatch");
data = dataStr;
} else {
throw new IllegalArgumentException("Unknown type");
}
Map<String, Object> obj = new HashMap<>();
obj.put("type", String.valueOf(type));
obj.put("name", name);
obj.put("rank", rank);
obj.put("dims", dims);
obj.put("data", data);
return obj;
}
private String serializeObject(Map<String, Object> obj) {
StringBuilder sb = new StringBuilder();
sb.append((String) obj.get("type")).append((String) obj.get("name")).append(" ");
sb.append(obj.get("rank")).append(" ");
@SuppressWarnings("unchecked")
List<Integer> dims = (List<Integer>) obj.get("dims");
sb.append(dims.stream().map(String::valueOf).collect(Collectors.joining(" ")));
sb.append(" ");
Object data = obj.get("data");
if (obj.get("type").equals("N")) {
@SuppressWarnings("unchecked")
List<Number> numData = (List<Number>) data;
sb.append(numData.stream().map(String::valueOf).collect(Collectors.joining(" ")));
} else {
sb.append((String) data);
}
return sb.toString();
}
}
4. JavaScript class
const fs = require('fs');
class AIOFile {
constructor() {
this.objects = []; // Array of objects: {type: string, name: string, rank: number, dims: number[], data: number[] or string}
}
open(filename, mode = 'r') {
if (mode === 'r') {
const content = fs.readFileSync(filename, 'utf8');
const lines = content.split('\n');
this.objects = [];
for (let line of lines) {
line = line.trim();
if (line) {
const obj = this._parseLine(line);
this.objects.push(obj);
}
}
} else if (mode === 'w') {
this.objects = [];
} else {
throw new Error("Mode must be 'r' or 'w'");
}
}
read() {
return this.objects;
}
write(objects) {
this.objects = objects;
}
save(filename) {
const content = this.objects.map(obj => this._serializeObject(obj)).join('\n');
fs.writeFileSync(filename, content, 'utf8');
}
_parseLine(line) {
let i = 0;
const type = line[i];
i++;
let start = i;
while (i < line.length && line[i] !== ' ') i++;
const name = line.slice(start, i);
if (i >= line.length || line[i] !== ' ') throw new Error("Invalid format");
i++;
start = i;
while (i < line.length && line[i] !== ' ') i++;
const rank = parseInt(line.slice(start, i), 10);
if (i >= line.length || line[i] !== ' ') throw new Error("Invalid format");
i++;
const dims = [];
for (let d = 0; d < rank; d++) {
start = i;
while (i < line.length && line[i] !== ' ') i++;
dims.push(parseInt(line.slice(start, i), 10));
if (i >= line.length || line[i] !== ' ') throw new Error("Invalid format");
i++;
}
const dataStr = line.slice(i);
const prod = dims.reduce((a, b) => a * b, 1) || 1;
let data;
if (type === 'N') {
const valuesStr = dataStr.trim().split(/\s+/);
if (valuesStr.length !== prod) throw new Error("Data length mismatch");
data = valuesStr.map(v => v.includes('.') || v.toUpperCase().includes('E') ? parseFloat(v) : parseInt(v, 10));
} else if (type === 'C' || type === 'F') {
if (dataStr.length !== prod) throw new Error("Data length mismatch");
data = dataStr;
} else {
throw new Error("Unknown type");
}
return {type, name, rank, dims, data};
}
_serializeObject(obj) {
let parts = [obj.type + obj.name, obj.rank.toString()];
parts = parts.concat(obj.dims.map(d => d.toString()));
let dataPart;
if (obj.type === 'N') {
dataPart = obj.data.map(v => v.toString()).join(' ');
} else {
dataPart = obj.data;
}
return parts.join(' ') + ' ' + dataPart;
}
}
5. C class
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <math.h>
// Simple dynamic array for dims and data (for N)
typedef struct {
char type;
char *name;
int rank;
int *dims;
void *data; // double* for N, char* for C/F
int is_numeric;
} AIOObject;
typedef struct {
AIOObject *objects;
int count;
int capacity;
} AIOFile;
AIOFile* aio_create() {
AIOFile* aio = malloc(sizeof(AIOFile));
aio->objects = NULL;
aio->count = 0;
aio->capacity = 0;
return aio;
}
void aio_destroy(AIOFile* aio) {
for (int j = 0; j < aio->count; j++) {
free(aio->objects[j].name);
free(aio->objects[j].dims);
if (aio->objects[j].is_numeric) {
free((double*)aio->objects[j].data);
} else {
free((char*)aio->objects[j].data);
}
}
free(aio->objects);
free(aio);
}
void aio_open(AIOFile* aio, const char* filename, const char* mode) {
if (strcmp(mode, "r") == 0) {
FILE* f = fopen(filename, "r");
if (!f) return;
char line[1024 * 1024]; // Assume large enough lines
aio->count = 0;
while (fgets(line, sizeof(line), f)) {
if (strlen(line) > 0 && line[strlen(line)-1] == '\n') line[strlen(line)-1] = '\0';
if (line[0] == '\0') continue;
if (aio->count >= aio->capacity) {
aio->capacity = aio->capacity ? aio->capacity * 2 : 8;
aio->objects = realloc(aio->objects, aio->capacity * sizeof(AIOObject));
}
aio_parse_line(aio, line, aio->count);
aio->count++;
}
fclose(f);
} else if (strcmp(mode, "w") == 0) {
aio->count = 0;
} else {
fprintf(stderr, "Invalid mode\n");
}
}
AIOObject* aio_read(AIOFile* aio, int* count) {
*count = aio->count;
return aio->objects;
}
void aio_write(AIOFile* aio, AIOObject* objects, int count) {
aio->count = count;
aio->objects = realloc(aio->objects, count * sizeof(AIOObject));
memcpy(aio->objects, objects, count * sizeof(AIOObject));
}
void aio_save(AIOFile* aio, const char* filename) {
FILE* f = fopen(filename, "w");
if (!f) return;
char buffer[1024 * 1024];
for (int j = 0; j < aio->count; j++) {
aio_serialize_object(&aio->objects[j], buffer, sizeof(buffer));
fprintf(f, "%s\n", buffer);
}
fclose(f);
}
void aio_parse_line(AIOFile* aio, const char* line, int idx) {
AIOObject* obj = &aio->objects[idx];
int i = 0;
obj->type = line[i++];
int start = i;
while (line[i] && line[i] != ' ') i++;
obj->name = strndup(&line[start], i - start);
if (!line[i]) goto error;
i++;
start = i;
while (line[i] && line[i] != ' ') i++;
obj->rank = atoi(&line[start]);
if (!line[i]) goto error;
i++;
obj->dims = malloc(obj->rank * sizeof(int));
int d = 0;
for (; d < obj->rank; d++) {
start = i;
while (line[i] && line[i] != ' ') i++;
obj->dims[d] = atoi(&line[start]);
if (!line[i]) goto error;
i++;
}
const char* data_str = &line[i];
long prod = 1;
for (int k = 0; k < obj->rank; k++) prod *= obj->dims[k];
if (prod == 0) prod = 1;
if (obj->type == 'N') {
obj->is_numeric = 1;
double* data = malloc(prod * sizeof(double));
char* tok = strtok((char*)data_str, " ");
int cnt = 0;
while (tok && cnt < prod) {
data[cnt++] = strstr(tok, ".") || strstr(tok, "E") || strstr(tok, "e") ? atof(tok) : atoi(tok);
tok = strtok(NULL, " ");
}
if (cnt != prod) goto error;
obj->data = data;
} else if (obj->type == 'C' || obj->type == 'F') {
obj->is_numeric = 0;
if (strlen(data_str) != prod) goto error;
obj->data = strdup(data_str);
} else {
goto error;
}
return;
error:
fprintf(stderr, "Parse error\n");
free(obj->name);
free(obj->dims);
}
void aio_serialize_object(AIOObject* obj, char* buffer, size_t bufsize) {
snprintf(buffer, bufsize, "%c%s %d", obj->type, obj->name, obj->rank);
char temp[128];
for (int d = 0; d < obj->rank; d++) {
snprintf(temp, sizeof(temp), " %d", obj->dims[d]);
strcat(buffer, temp);
}
strcat(buffer, " ");
if (obj->is_numeric) {
double* data = (double*)obj->data;
for (int k = 0; k < (obj->rank ? 1 : 1); /* prod calculated earlier, but loop over */ ) {
long prod = 1;
for (int m = 0; m < obj->rank; m++) prod *= obj->dims[m];
for (int k = 0; k < prod; k++) {
if (fmod(data[k], 1.0) == 0) {
snprintf(temp, sizeof(temp), "%d ", (int)data[k]);
} else {
snprintf(temp, sizeof(temp), "%g ", data[k]);
}
strcat(buffer, temp);
}
return; // Trim last space if needed
}
} else {
strcat(buffer, (char*)obj->data);
}
}