diff options
| author | Jacob McDonnell <jacob@jacobmcdonnell.com> | 2026-04-04 17:41:01 -0400 |
|---|---|---|
| committer | Jacob McDonnell <jacob@jacobmcdonnell.com> | 2026-04-04 17:41:01 -0400 |
| commit | 20e247e31fb40bf2228a2ed84b93896fc48b5eff (patch) | |
| tree | 91f721c57a0565b66eae16562e1fbbf9a588d324 | |
| parent | 0ead69cdfa8886775212a85fed3aa962fc22902a (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-- | Makefile | 21 | ||||
| -rw-r--r-- | example.mat | bin | 0 -> 192 bytes | |||
| -rw-r--r-- | include/matfile.h | 92 | ||||
| -rw-r--r-- | src/main.c | 61 | ||||
| -rw-r--r-- | src/matfile.c | 52 | ||||
| -rw-r--r-- | test.mat | bin | 0 -> 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 Binary files differnew file mode 100644 index 0000000..28494a0 --- /dev/null +++ b/example.mat 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 Binary files differnew file mode 100644 index 0000000..a338ead --- /dev/null +++ b/test.mat |
