/* SPDX-License-Identifier: GPL-3.0-or-later */ /* Copyright (C) 2021 KikooDX */ #include #include #include #include "level.h" /* globals are needed when using gint_switch() */ tile_t level[LEVEL_SIZE]; int level_id = 0; int fatal_error = 0; char *fatal_error_msg = "no error, happy kikoo :D"; int debug_value = 0; static const uint16_t *filepath = u"\\\\fls0\\sample.kble"; static int read_byte(int file); static tile_t read_merge_bytes(int file, int size); /* Load level from storage memory. */ void level_load(void) { int file; int tile_size; int width; int height; int file_size; int i; char byte; tile_t tile; /* open file read only */ file = BFile_Open(filepath, BFile_ReadOnly); assert(file >= 0, "can't open file " "don't forget to put it on the calculator dummy"); /* assert KBLE format version */ byte = read_byte(file); assert(byte == kble_format_version, "kble format version doesn't match"); /* get tile size (in bytes) */ tile_size = read_byte(file); assert(tile_size >= 0, "can't read tile size"); assert((unsigned int)tile_size <= sizeof(tile_t), "tiles are too heavy"); /* assert than width and height are correct */ width = read_merge_bytes(file, 2); height = read_merge_bytes(file, 2); assert(width >= 0, "can't read level width"); assert(width == LEVEL_WIDTH, "invalid level width"); assert(height >= 0, "can't read level height"); assert(height == LEVEL_HEIGHT, "invalid level height"); /* using those informations, see if the file size make sense */ file_size = BFile_Size(file); assert(file_size >= 0, "can't read file size"); assert(file_size == kble_header_len + LEVEL_SIZE * tile_size, "file size doesn't make sense"); /* read file content */ for (i = 0; i < LEVEL_SIZE; i += 1) { tile = read_merge_bytes(file, tile_size); assert(tile != (tile_t)-1, "can't read tile"); level[i] = tile; } /* close file */ file = BFile_Close(file); assert(file >= 0, "closure failed miserably"); } /* Save level to memory. Allocate memory to write everything at once. */ void level_save(void) { int file; unsigned int tile_size; unsigned int max_tile_size = 1; int i; tile_t tile; int data_size; char *data = NULL; /* find appropriate tile size */ for (i = 0; i < LEVEL_SIZE; i += 1) { tile = level[i]; tile_size = 1; while (tile >>= 8) tile_size += 1; if (tile_size > max_tile_size) max_tile_size = tile_size; } assert(max_tile_size <= sizeof(tile_t), "computed tile size is crazy"); /* total amount of data to write in bytes */ data_size = kble_header_len + LEVEL_SIZE * tile_size; /* allocate memory */ data = malloc(data_size); /* kble format version */ data[0] = kble_format_version; /* tile size in bytes */ data[1] = max_tile_size; /* width and height (comptime) */ data[2] = LEVEL_WIDTH / 256; data[3] = LEVEL_WIDTH % 256; data[4] = LEVEL_HEIGHT / 256; data[5] = LEVEL_HEIGHT % 256; /* level content */ assert(max_tile_size == 1, "this editor only support tiles from 0 to 255"); for (i = 0; i < LEVEL_SIZE; i += 1) { data[i + kble_header_len] = level[i]; } /* open file in write mode */ file = BFile_Open(filepath, BFile_WriteOnly); assert(file >= 0, "can't open file in write mode"); /* recreate file with correct size if needed */ if (BFile_Size(file) != data_size) { int data_size_copy = data_size; /* close file */ file = BFile_Close(file); assert(file >= 0, "closure failed miserably (w)"); /* remove file */ file = BFile_Remove(filepath); assert(file >= 0, "file removal failed somehow"); /* create file */ file = BFile_Create(filepath, BFile_File, &data_size_copy); assert(file >= 0, "file creation failed :("); assert(data_size == data_size_copy, "casio messed up my data_size variable"); /* open file */ file = BFile_Open(filepath, BFile_WriteOnly); assert(file >= 0, "can't open file in write mode"); } /* write data */ BFile_Write(file, data, data_size); /* close file */ file = BFile_Close(file); assert(file >= 0, "closure failed miserably (w)"); /* free memory */ free(data); } /* Read a single byte. Negative value is BFile error code. */ static int read_byte(int file) { char byte; const int error = BFile_Read(file, &byte, sizeof(char), -1); if (error < 0) return error; else return byte; } /* Read multiple bytes and merge them as one integer. * Return -1 on failure. */ static tile_t read_merge_bytes(int file, int size) { tile_t merged = 0; int byte = 0; char *byte_ptr = (char*)&merged; int i = 0; byte_ptr += sizeof(tile_t) - size; for (i = 0; i < size; i += 1) { byte = read_byte(file); if (byte < 0) return -1; *byte_ptr = byte; byte_ptr += 1; } return merged; }