#include #include "puzzle.h" #include #include #include #include #include /// Reads a uint8_t from file. /// Assumes that the file is on the position uint8_t read_u8(FILE *file) { uint8_t outp; fread(&outp, 1, 1, file); return outp; } /// Reads a uint32_t (little-endian) from file. /// Assumes that the file is on the position uint32_t read_u32(FILE *file) { uint32_t outp = 0; for (int i = 0; i < 4; i++) { outp += ((uint32_t)read_u8(file)) << (i * 8); } return outp; } /// Reads a double from file. /// Assumes that the file is on the position double read_double(FILE *file) { double outp; fread(&outp, sizeof(double), 1, file); return outp; } /// Reads a null terminated string from file. /// Assumes that the file if on the position. /// Allocates the string. char *read_string(FILE *file) { char buf[8192]; size_t idx = 0; int c; while (idx < sizeof(buf) - 1) { c = fgetc(file); if (c == 0 || c == EOF) break; buf[idx] = (char)c; idx += 1; } buf[idx] = 0x0; return strdup(buf); } typedef enum { TYPE_NULL = 0, TYPE_BOOL = 1, TYPE_NUM = 2, TYPE_STRING = 3, TYPE_LIST = 4, } V1_IO_TYPE; void ReadPuzzleIO_V1(FILE *file, PuzzleIO *io) { uint8_t type = read_u8(file); switch (type) { case TYPE_NULL: // NULL io->type = WREN_TYPE_NULL; io->value = NULL; break; case TYPE_BOOL: { bool *outp = malloc(sizeof(bool)); *outp = read_u8(file) != 0; io->type = WREN_TYPE_BOOL; io->value = outp; break; } case TYPE_NUM: { double *outp = malloc(sizeof(double)); *outp = read_double(file); io->type = WREN_TYPE_NUM; io->value = outp; break; } case TYPE_STRING: io->type = WREN_TYPE_STRING; io->value = read_string(file); break; case TYPE_LIST: TraceLog(LOG_ERROR, "The arrays are not yet supported"); io->type = WREN_TYPE_NULL; io->value = NULL; break; default: return; } } void readTestV1(FILE *file, Test *outp) { outp->RecieverName = read_string(file); outp->MainMethodSignature = read_string(file); outp->argc = read_u32(file); outp->argv = malloc(sizeof(PuzzleIO) * outp->argc); for (size_t i = 0; i < outp->argc; i++) { ReadPuzzleIO_V1(file, &outp->argv[i]); } ReadPuzzleIO_V1(file, &outp->ExpectedResult); } // Reads file with the specification from puzzle_specs_v1.md. // Assumes the first byte of the file was read and the file was not rewinded. Puzzle *parseFileV1(FILE *file) { Puzzle *outp = malloc(sizeof(Puzzle)); if (outp == NULL) return NULL; outp->Name = read_string(file); outp->Description = read_string(file); outp->InitialCode = read_string(file); outp->TestC = read_u32(file); outp->Tests = malloc(sizeof(Test) * outp->TestC); for (size_t i = 0; i < outp->TestC; i++) { readTestV1(file, &outp->Tests[i]); } return outp; } Puzzle *ReadPuzzleFromFile(const char *path) { FILE *file = fopen(path, "r"); if (file == NULL) { perror("Failed to parse the puzzle file"); return NULL; } uint8_t spec_version = read_u8(file); printf("Version: %d\n", spec_version); Puzzle *outp = NULL; switch (spec_version) { case 1: outp = parseFileV1(file); break; default: TraceLog(LOG_ERROR, "Failed to parse the puzzle file: unknown spec version"); break; } fclose(file); return outp; }