summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJacob McDonnell <jacob@jacobmcdonnell.com>2026-04-04 17:41:01 -0400
committerJacob McDonnell <jacob@jacobmcdonnell.com>2026-04-04 17:41:01 -0400
commit20e247e31fb40bf2228a2ed84b93896fc48b5eff (patch)
tree91f721c57a0565b66eae16562e1fbbf9a588d324
parent0ead69cdfa8886775212a85fed3aa962fc22902a (diff)
feat: Producing a Readable MAT-File
Producing a readable MAT-File of a 1x5 Array of doubles. The file is somewhat manually generated, but currently works.
-rw-r--r--Makefile21
-rw-r--r--example.matbin0 -> 192 bytes
-rw-r--r--include/matfile.h92
-rw-r--r--src/main.c61
-rw-r--r--src/matfile.c52
-rw-r--r--test.matbin0 -> 224 bytes
6 files changed, 226 insertions, 0 deletions
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..7746ba9
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,21 @@
+CC = gcc-15
+CFLAGS = -std=c17 \
+ -Wall \
+ -Werror \
+ -Wextra \
+ -Wpedantic \
+ -Iinclude
+SRCS = src/main.c \
+ src/matfile.c
+PROG = main
+
+all: $(PROG)
+
+$(PROG): $(SRCS)
+ $(CC) $(CFLAGS) -o $@ $^
+
+clean:
+ rm -rf $(PROG)
+
+.PHONY: all clean
+
diff --git a/example.mat b/example.mat
new file mode 100644
index 0000000..28494a0
--- /dev/null
+++ b/example.mat
Binary files differ
diff --git a/include/matfile.h b/include/matfile.h
new file mode 100644
index 0000000..586dbea
--- /dev/null
+++ b/include/matfile.h
@@ -0,0 +1,92 @@
+#ifndef INCLUDE_MATFILE_H_
+#define INCLUDE_MATFILE_H_
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <stdio.h>
+
+typedef enum {
+ miINT8 = 1,
+ miUINT8 = 2,
+ miINT16 = 3,
+ miUINT16 = 4,
+ miINT32 = 5,
+ miUINT32 = 6,
+ miSINGLE = 7,
+ // 8 -- Reserved
+ miDOUBLE = 9,
+ // 10 -- Reserved
+ // 11 -- Reserved
+ miINT64 = 12,
+ miUINT64 = 13,
+ miMATRIX = 14,
+ miCOMPRESSED = 15,
+ miUTF8 = 16,
+ miUTF16 = 17,
+ miUTF32 = 18
+} mTypes_t;
+
+typedef enum {
+ mxCELL_CLASS = 1,
+ mxSTRUCT_CLASS = 2,
+ mxOBJECT_CLASS = 3,
+ mxCHAR_CLASS = 4,
+ mxSPARSE_CLASS = 5,
+ mxDOUBLE_CLASS = 6,
+ mxSINGLE_CLASS = 7,
+ mxINT8_CLASS = 8,
+ mxUINT8_CLASS = 9,
+ mxINT16_CLASS = 10,
+ mxUINT16_CLASS = 11,
+ mxINT32_CLASS = 12,
+ mxUINT32_CLASS = 13,
+ mxINT64_CLASS = 14,
+ mxUINT64_CLASS = 15,
+} mClasses_t;
+
+typedef struct {
+ char description[116];
+ uint32_t subsystem_offset_high;
+ uint32_t subsystem_offset_low;
+ uint16_t version;
+ uint16_t endian_indicator;
+} mHeader_t;
+
+typedef struct {
+ uint32_t type;
+ uint32_t size;
+} mTag_t;
+
+typedef struct {
+ uint16_t type;
+ uint16_t size;
+} mSmallTag_t;
+
+typedef struct {
+ mTag_t tag;
+ void *data;
+} mData_t;
+
+typedef struct {
+ mSmallTag_t tag;
+ uint32_t data;
+} mSmallData_t;
+
+typedef struct {
+ uint8_t class;
+ struct {
+ uint8_t unused1 : 1;
+ uint8_t logical : 1;
+ uint8_t global : 1;
+ uint8_t complex : 1;
+ uint8_t unused2 : 4;
+ };
+ uint16_t unused3;
+ uint32_t unused0;
+} mArrayFlags_t;
+
+bool write_header(FILE *file);
+bool write_data(FILE *file, mData_t data);
+bool write_small_data(FILE *file, mSmallData_t data);
+
+#endif // INCLUDE_MATFILE_H_
diff --git a/src/main.c b/src/main.c
new file mode 100644
index 0000000..9b6d69d
--- /dev/null
+++ b/src/main.c
@@ -0,0 +1,61 @@
+#include <stdio.h>
+#include <assert.h>
+#include <string.h>
+#include "matfile.h"
+
+double floats[5] = {0.0, 1.0, 3.14, 2.72, 5.5};
+
+int main(void) {
+ FILE *fp = fopen("test.mat", "w");
+ if (fp == NULL) {
+ perror("fopen");
+ return -1;
+ }
+
+ // Write File Header
+ assert(write_header(fp));
+
+ // Setup Array Dimensions
+ int32_t dims[2] = {1, 5};
+ mData_t dim_data;
+ dim_data.data = (void *)&dims;
+ dim_data.tag.type = miINT32;
+ dim_data.tag.size = 8;
+
+ // Array Flags
+ mArrayFlags_t flags;
+ memset(&flags, 0, sizeof(flags));
+ flags.global = 0;
+ flags.complex = 0;
+ flags.logical = 0;
+ flags.class = mxDOUBLE_CLASS;
+
+ mData_t flags_data;
+ flags_data.tag.type = miUINT32;
+ flags_data.tag.size = 8;
+ flags_data.data = (void *)&flags;
+
+ // Name
+ mSmallData_t name;
+ name.tag.type = miINT8;
+ name.tag.size = 1;
+ name.data = 'A';
+
+ mData_t data;
+ data.tag.type = miDOUBLE;
+ data.tag.size = sizeof(floats);
+ data.data = (void *)floats;
+
+ mTag_t array;
+ array.type = miMATRIX;
+ array.size = 96;
+
+ fwrite((void *)&array, 1, sizeof(array), fp);
+ write_data(fp, flags_data);
+ write_data(fp, dim_data);
+ write_small_data(fp, name);
+ write_data(fp, data);
+
+ fclose(fp);
+ return 0;
+}
diff --git a/src/matfile.c b/src/matfile.c
new file mode 100644
index 0000000..188e14f
--- /dev/null
+++ b/src/matfile.c
@@ -0,0 +1,52 @@
+#include "matfile.h"
+#include <string.h>
+#include <time.h>
+#include <stdlib.h>
+
+static const char *const default_description = "MATLAB 5.0 MAT-file, Created on: ";
+
+bool write_header(FILE *file) {
+ if (file == NULL) {
+ return false;
+ }
+
+ mHeader_t header;
+ memset((void *)&header, 0, sizeof(header));
+ memset((void *)header.description, ' ', sizeof(header.description));
+
+ time_t t = time(NULL);
+ const char *const strtime = ctime(&t);
+
+ snprintf(header.description, sizeof(header.description), "%s%s", default_description, strtime);
+
+ header.version = 0x0100;
+ header.endian_indicator = (('M' << 8) | 'I');
+
+ const size_t status = fwrite((const void *)&header, 1, sizeof(header), file);
+
+ return (status == sizeof(header));
+}
+
+bool write_data(FILE *file, const mData_t data) {
+ if (data.data == NULL) {
+ return false;
+ }
+
+ bool success = true;
+ success = (fwrite((const void *)&data.tag, 1, sizeof(data.tag), file) == sizeof(data.tag)) && success;
+ success = (fwrite(data.data, 1, data.tag.size, file) == data.tag.size) && success;
+
+ const size_t padding = data.tag.size % 8;
+ const uint8_t padding_buffer[8] = {0};
+ if (padding > 0 && success) {
+ success = (fwrite((const void *)padding_buffer, 1, padding, file) == padding) && success;
+ }
+
+ return success;
+}
+
+bool write_small_data(FILE *file, const mSmallData_t data) {
+ const size_t w = fwrite((const void *)&data, 1, sizeof(data), file);
+
+ return (w == sizeof(data));
+} \ No newline at end of file
diff --git a/test.mat b/test.mat
new file mode 100644
index 0000000..a338ead
--- /dev/null
+++ b/test.mat
Binary files differ