feat: Implement narc_strerror, narc_load

This commit is contained in:
Rachel 2024-12-27 00:06:09 -08:00
parent 318a3249b8
commit ee38b71c3b
6 changed files with 201 additions and 0 deletions

View File

@ -1,6 +1,7 @@
--- ---
BasedOnStyle: LLVM BasedOnStyle: LLVM
Language: Cpp Language: Cpp
AlignConsecutiveMacros: Consecutive
AlignOperands: false AlignOperands: false
BraceWrapping: BraceWrapping:
AfterCaseLabel: false AfterCaseLabel: false

3
.gitignore vendored
View File

@ -13,3 +13,6 @@ compile_commands.json
# Valgrind output # Valgrind output
valgrind.log valgrind.log
# Testing files
*.narc

71
include/narc.h Normal file
View File

@ -0,0 +1,71 @@
/*
* Copyright 2024 <lhearachel@proton.me>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef NARC_H
#define NARC_H
#include <stdint.h>
enum narc_error {
NARCERR_NONE = 0,
NARCERR_MAGIC,
NARCERR_BOM,
NARCERR_VERSION,
NARCERR_HEADER_SIZE,
NARCERR_NUM_SECTIONS,
NARCERR_ERRNO = 0xFF,
};
struct narc {
uint32_t magic;
uint16_t bom;
uint16_t version;
uint32_t size;
uint16_t header_size;
uint16_t num_sections;
unsigned char data[];
};
/*
* Convert a `narc_error` value into a corresponding human-readable message.
*/
const char *narc_strerror(enum narc_error error);
/*
* Load a NARC from an existing file at the given path. If the file contents
* validate as a NARC, then `out_narc` will be set to an address with sufficient
* memory allocation to hold the entire file. The calling client is responsible
* for freeing this allocation.
*
* Any of the following error codes may be emitted:
*
* - `NARCERR_NONE` - No error; `narc` contains good data.
* - `NARCERR_MAGIC` - The magic ID in the file's header did not match
* expectations.
* - `NARCERR_BOM` - The byte-order marker in the file's header did
* not match expectations.
* - `NARCERR_VERSION` - The version marker in the file's header did not
* match expectations.
* - `NARCERR_HEADER_SIZE` - The file's header reports an invalid size for
* itself.
* - `NARCERR_NUM_SECTIONS` - The number of sections expected by the file's
* header did not match expectations.
* - `NARCERR_ERRNO` - A system-level error occurred; consult `errno`.
*/
enum narc_error narc_load(const char *file_path, struct narc **out_narc);
#endif // NARC_H

50
src/cli.c Normal file
View File

@ -0,0 +1,50 @@
/*
* Copyright 2024 <lhearachel@proton.me>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <assert.h>
#include <errno.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "narc.h"
int main(void)
{
struct narc *narc = NULL;
enum narc_error err = narc_load("test.narc", &narc);
if (err == NARCERR_ERRNO) {
fprintf(stderr, "System error: %s\n", strerror(errno));
fflush(stderr);
return EXIT_FAILURE;
} else if (err != NARCERR_NONE) {
fprintf(stderr, "NARC error: %s\n", narc_strerror(err));
fflush(stderr);
return EXIT_FAILURE;
}
printf("Loaded NARC successfully!\n");
printf("NARC size: %d\n", narc->size);
printf("NARC data sample:");
for (int i = 0; i < 16; i++) {
printf(" %02x", narc->data[i]);
}
printf("\n");
free(narc);
return EXIT_SUCCESS;
}

54
src/narc_load.c Normal file
View File

@ -0,0 +1,54 @@
#include "narc.h"
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define NARC_MAGIC 0x4352414E
#define LE_BOM 0xFFFE
#define VERSION_MARKER 0x0100
#define HEADER_SIZE 16
#define NUM_SECTIONS 3
#define ERROR_NEQ(expect, actual, err, file) \
{ \
if ((expect) != (actual)) { \
fclose(file); \
return err; \
} \
}
enum narc_error narc_load(const char *file_path, struct narc **out_narc)
{
FILE *f = fopen(file_path, "rb");
if (f == NULL) {
return NARCERR_ERRNO;
}
fseek(f, 0, SEEK_END);
size_t fsize = ftell(f);
fseek(f, 0, SEEK_SET);
// Validate the header.
struct narc header;
fread(&header, sizeof(char), HEADER_SIZE, f);
ERROR_NEQ(NARC_MAGIC, header.magic, NARCERR_MAGIC, f);
ERROR_NEQ(LE_BOM, header.bom, NARCERR_BOM, f);
ERROR_NEQ(VERSION_MARKER, header.version, NARCERR_VERSION, f);
ERROR_NEQ(HEADER_SIZE, header.header_size, NARCERR_HEADER_SIZE, f);
ERROR_NEQ(NUM_SECTIONS, header.num_sections, NARCERR_NUM_SECTIONS, f);
// Header is good; allocate enough memory to hold the whole file.
*out_narc = malloc(fsize);
if (*out_narc == NULL) {
fclose(f);
return NARCERR_ERRNO;
}
memcpy(*out_narc, &header, sizeof(header));
fread((*out_narc)->data, sizeof(char), fsize - sizeof(header), f);
fclose(f);
return NARCERR_NONE;
}

22
src/narc_strerror.c Normal file
View File

@ -0,0 +1,22 @@
#include "narc.h"
const char *narc_strerror(enum narc_error error)
{
switch (error) {
default:
case NARCERR_NONE:
return "(null)";
case NARCERR_MAGIC:
return "Invalid magic marker in NARC header";
case NARCERR_BOM:
return "Invalid byte-order marker in NARC header";
case NARCERR_VERSION:
return "Invalid version marker in NARC header";
case NARCERR_HEADER_SIZE:
return "Invalid NARC header size";
case NARCERR_NUM_SECTIONS:
return "Invalid section count in NARC header";
case NARCERR_ERRNO:
return "Standard error; refer to errno for details";
}
}