<commit_before>/*
 * Copyright (c) 2020 <NAME> <<EMAIL>>
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#include <sys/types.h>

#include <assert.h>
#include <ctype.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "memLoader.h"
#include "memory.h"
#include "logger.h"
#include "strtonum.h"
#include "tools.h"

#define LINE_LEN		16
#define MIN_LINE_LEN		14
#define MAX_LINE_LEN		32

#ifndef nitems
#define nitems(_a) (sizeof((_a)) / sizeof((_a)[0]))
#endif

struct memory_record {
	char		*line;		/* contents of 1 line from file */
	size_t		 linesize;	/* size of the line string */
	ssize_t		 linelen;	/* length of the line */
	int		 lineno;	/* line number from the file */
	int		 memaddress;	/* memory address (on word boundry) */
	int		 prevaddress;	/* previous line's memory address */
	unsigned int	 data;		/* data to store in memory */
	unsigned int	 prevdata;	/* previous line's data */
	int		 starline;	/* does line have a '*'? */
	int		 prevstarline;	/* did previous line have a '*'? */
};

static int validatememfilename(const char *filename);
static int validateline(struct memory_record *);
static bool hashexdigits(const char *line, ssize_t len, int start, int end);
static int readaddress(const char *line, int *error);
static unsigned int readdata(const char *line, int *error);
static unsigned int strtouint(const char *nptr, int base, int *error);
static int putrepeatdata(const struct memory_record * const record);

/*
 * Load a memory image from a file.
 */
bool
load_mem_image(const char *fileName)
{
	FILE *fp;

	if (validatememfilename(fileName) == -1) {
		return FALSE; /* EXIT */
	}

	/* open file as read-only */
	log_debug("opening file \'%s\'", fileName);
	fp = fopen(fileName, "r");
	if (fp == NULL) {
		log_warn("error opening the file");
		return FALSE; /* EXIT */
	}

	log_info("reading contents into memory");

	struct memory_record record = {
		.line = NULL,
		.linesize = 0,
		.lineno = 1,
		.prevaddress = -1,	/* starting address */
		.prevstarline = 0
	};

	/* attempt to load each line of the file into memory */
	while ((record.linelen = getline(&record.line, &record.linesize, fp)) != -1) {
		if (validateline(&record) == -1) {
			/* display the erroneous line */
			printf("Error on line %d:\n", record.lineno);
			printf("%s\n", record.line);
			goto error;
		}

		int error;
		record.data = readdata(record.line, &error);
		if (error) {
			log_info("error reading data on line %d",
			    record.lineno);
			goto error;
		}

		/*
		 * If previous line had a '*', then all addresses up to
		 * the current line's address will contain the previous
		 * line's data.
		 */
		if (record.prevstarline) {
			if (putrepeatdata(&record) == -1) {
				goto error;
			}
		}

		/* now store current line */
		bool memError;
		putWord(record.memaddress, record.data, &memError);
		if (memError) {
			log_info("error storing data at address %04x",
			    record.memaddress);
			goto error;
		}

		record.prevaddress = record.memaddress;
		record.prevdata = record.data;
		record.prevstarline = record.starline;
		record.lineno++;
	}

	free(record.line);
	log_debug("closing file");
	fclose(fp);
	return TRUE;

error:
	free(record.line);
	log_debug("closing file");
	fclose(fp);
	return FALSE;
}

/*
 * Validate that the given filename ends in ".mem"
 *
 * Parameters:
 *	*filename    filename to check
 *
 * Return >0 if file ends in ".mem"; -1 otherwise
 */
int
validatememfilename(const char *filename)
{
#ifdef AFL_TEST
	return 1;
#endif
	assert(filename != NULL);

	int len = (int)strnlen(filename, FILENAME_LEN);

	if (len < 4) {
		log_warn("filename too short");
		return -1;
	}

	if (filename[len - 1] == 'm'
	    && filename[len - 2] == 'e'
	    && filename[len - 3] == 'm'
	    && filename[len - 4] == '.') {
		log_debug("filename valid");
		return 1;
	}
	else {
		log_warn("filename not valid");
		return -1;
	}
}

/*
 * Determine if the line from the file is in the correct
 * format. Also validates that the memory address is<commit_msg>use strrchr() and strcmp() to compare .mem files also<commit_after>/*
 * Copyright (c) 2020 <NAME> <<EMAIL>>
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#include <sys/types.h>

#include <assert.h>
#include <ctype.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "memLoader.h"
#include "memory.h"
#include "logger.h"
#include "strtonum.h"
#include "tools.h"

#define LINE_LEN		16
#define MIN_LINE_LEN		14
#define MAX_LINE_LEN		32

#ifndef nitems
#define nitems(_a) (sizeof((_a)) / sizeof((_a)[0]))
#endif

struct memory_record {
	char		*line;		/* contents of 1 line from file */
	size_t		 linesize;	/* size of the line string */
	ssize_t		 linelen;	/* length of the line */
	int		 lineno;	/* line number from the file */
	int		 memaddress;	/* memory address (on word boundry) */
	int		 prevaddress;	/* previous line's memory address */
	unsigned int	 data;		/* data to store in memory */
	unsigned int	 prevdata;	/* previous line's data */
	int		 starline;	/* does line have a '*'? */
	int		 prevstarline;	/* did previous line have a '*'? */
};

static int validatememfilename(const char *filename);
static int validateline(struct memory_record *);
static bool hashexdigits(const char *line, ssize_t len, int start, int end);
static int readaddress(const char *line, int *error);
static unsigned int readdata(const char *line, int *error);
static unsigned int strtouint(const char *nptr, int base, int *error);
static int putrepeatdata(const struct memory_record * const record);

/*
 * Load a memory image from a file.
 */
bool
load_mem_image(const char *fileName)
{
	FILE *fp;

	if (validatememfilename(fileName) == -1) {
		return FALSE; /* EXIT */
	}

	/* open file as read-only */
	log_debug("opening file \'%s\'", fileName);
	fp = fopen(fileName, "r");
	if (fp == NULL) {
		log_warn("error opening the file");
		return FALSE; /* EXIT */
	}

	log_info("reading contents into memory");

	struct memory_record record = {
		.line = NULL,
		.linesize = 0,
		.lineno = 1,
		.prevaddress = -1,	/* starting address */
		.prevstarline = 0
	};

	/* attempt to load each line of the file into memory */
	while ((record.linelen = getline(&record.line, &record.linesize, fp)) != -1) {
		if (validateline(&record) == -1) {
			/* display the erroneous line */
			printf("Error on line %d:\n", record.lineno);
			printf("%s\n", record.line);
			goto error;
		}

		int error;
		record.data = readdata(record.line, &error);
		if (error) {
			log_info("error reading data on line %d",
			    record.lineno);
			goto error;
		}

		/*
		 * If previous line had a '*', then all addresses up to
		 * the current line's address will contain the previous
		 * line's data.
		 */
		if (record.prevstarline) {
			if (putrepeatdata(&record) == -1) {
				goto error;
			}
		}

		/* now store current line */
		bool memError;
		putWord(record.memaddress, record.data, &memError);
		if (memError) {
			log_info("error storing data at address %04x",
			    record.memaddress);
			goto error;
		}

		record.prevaddress = record.memaddress;
		record.prevdata = record.data;
		record.prevstarline = record.starline;
		record.lineno++;
	}

	free(record.line);
	log_debug("closing file");
	fclose(fp);
	return TRUE;

error:
	free(record.line);
	log_debug("closing file");
	fclose(fp);
	return FALSE;
}

/*
 * Validate that the given filename ends in ".mem"
 *
 * Parameters:
 *	*filename    filename to check
 *
 * Return >0 if file ends in ".mem"; -1 otherwise
 */
int
validatememfilename(const char *filename)
{
#ifdef AFL_TEST
	return 1;
#endif
	assert(filename != NULL);
	char *p;

	size_t len = strnlen(filename, FILENAME_LEN);

	if (len < 4) {
		log_warn("filename too short");
		return -1;
	}

	p = strrchr(filename, '.');
	if (p == NULL || strcmp(p, ".mem")) {
		log_warn("filename not valid");
		return -1;
	}
	else {
		log_debug("filename valid");
		return 1;
	}
}

/*
 * Determine if the line from the file is in the correct
 * format. Also validates that the memory address is
{'fraction_non_alphanumeric': 0.12691652470187392, 'fraction_numerical': 0.006601362862010221, 'mean_word_length': 3.5708029197080293, 'pattern_counts': {'":': 0, '<': 25, '<?xml version=': 0, '>': 25, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '865741', 'n_tokens_mistral': 3351, 'n_tokens_neox': 3047, 'n_words': 1082}