mirror of
https://github.com/n64decomp/sm64.git
synced 2024-11-13 21:05:03 -05:00
289 lines
6.0 KiB
C
289 lines
6.0 KiB
C
#include <dirent.h>
|
|
#include <fcntl.h>
|
|
#include <stdint.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <sys/stat.h>
|
|
#if defined(_MSC_VER) || defined(__MINGW32__)
|
|
#include <io.h>
|
|
#include <sys/utime.h>
|
|
#else
|
|
#include <unistd.h>
|
|
#include <utime.h>
|
|
#endif
|
|
|
|
#include "utils.h"
|
|
|
|
// global verbosity setting
|
|
int g_verbosity = 0;
|
|
|
|
int read_s16_be(unsigned char *buf)
|
|
{
|
|
unsigned tmp = read_u16_be(buf);
|
|
int ret;
|
|
if (tmp > 0x7FFF) {
|
|
ret = -((int)0x10000 - (int)tmp);
|
|
} else {
|
|
ret = (int)tmp;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
float read_f32_be(unsigned char *buf)
|
|
{
|
|
union {uint32_t i; float f;} ret;
|
|
ret.i = read_u32_be(buf);
|
|
return ret.f;
|
|
}
|
|
|
|
int is_power2(unsigned int val)
|
|
{
|
|
while (((val & 1) == 0) && (val > 1)) {
|
|
val >>= 1;
|
|
}
|
|
return (val == 1);
|
|
}
|
|
|
|
int fprint_write_output(FILE *fp, write_encoding encoding, const uint8_t *raw, int length)
|
|
{
|
|
typedef struct {
|
|
int bytes_per_val;
|
|
const char *suffix;
|
|
} encoding_format;
|
|
const encoding_format enc_fmt[] = {
|
|
[ENCODING_RAW] = {0, ""},
|
|
[ENCODING_U8] = {sizeof(uint8_t), ""},
|
|
[ENCODING_U16] = {sizeof(uint16_t), ""},
|
|
[ENCODING_U32] = {sizeof(uint32_t), ""},
|
|
[ENCODING_U64] = {sizeof(uint64_t), "ULL"},
|
|
};
|
|
int flength = 0;
|
|
const encoding_format *fmt = &enc_fmt[encoding];
|
|
switch (encoding) {
|
|
case ENCODING_RAW:
|
|
flength = fwrite(raw, 1, length, fp);
|
|
break;
|
|
case ENCODING_U8:
|
|
case ENCODING_U16:
|
|
case ENCODING_U32:
|
|
case ENCODING_U64:
|
|
for (int w = 0; w < length; w += fmt->bytes_per_val) {
|
|
flength += fprintf(fp, "0x");
|
|
for (int b = 0; b < fmt->bytes_per_val; b++) {
|
|
int off = w + b;
|
|
flength += fprintf(fp, "%02x", off < length ? raw[off] : 0x00);
|
|
}
|
|
flength += fprintf(fp, "%s%c", fmt->suffix, (w < length - fmt->bytes_per_val) ? ',' : '\n');
|
|
}
|
|
break;
|
|
}
|
|
return flength;
|
|
}
|
|
|
|
void swap_bytes(unsigned char *data, long length)
|
|
{
|
|
long i;
|
|
unsigned char tmp;
|
|
for (i = 0; i < length; i += 2) {
|
|
tmp = data[i];
|
|
data[i] = data[i+1];
|
|
data[i+1] = tmp;
|
|
}
|
|
}
|
|
|
|
void reverse_endian(unsigned char *data, long length)
|
|
{
|
|
long i;
|
|
unsigned char tmp;
|
|
for (i = 0; i < length; i += 4) {
|
|
tmp = data[i];
|
|
data[i] = data[i+3];
|
|
data[i+3] = tmp;
|
|
tmp = data[i+1];
|
|
data[i+1] = data[i+2];
|
|
data[i+2] = tmp;
|
|
}
|
|
}
|
|
|
|
long filesize(const char *filename)
|
|
{
|
|
struct stat st;
|
|
|
|
if (stat(filename, &st) == 0) {
|
|
return st.st_size;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
void touch_file(const char *filename)
|
|
{
|
|
int fd;
|
|
//fd = open(filename, O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK, 0666);
|
|
fd = open(filename, O_WRONLY|O_CREAT, 0666);
|
|
if (fd >= 0) {
|
|
utime(filename, NULL);
|
|
close(fd);
|
|
}
|
|
}
|
|
|
|
long read_file(const char *file_name, unsigned char **data)
|
|
{
|
|
FILE *in;
|
|
unsigned char *in_buf = NULL;
|
|
long file_size;
|
|
long bytes_read;
|
|
in = fopen(file_name, "rb");
|
|
if (in == NULL) {
|
|
return -1;
|
|
}
|
|
|
|
// allocate buffer to read from offset to end of file
|
|
fseek(in, 0, SEEK_END);
|
|
file_size = ftell(in);
|
|
|
|
// sanity check
|
|
if (file_size > 256*MB) {
|
|
return -2;
|
|
}
|
|
|
|
in_buf = malloc(file_size);
|
|
fseek(in, 0, SEEK_SET);
|
|
|
|
// read bytes
|
|
bytes_read = fread(in_buf, 1, file_size, in);
|
|
if (bytes_read != file_size) {
|
|
return -3;
|
|
}
|
|
|
|
fclose(in);
|
|
*data = in_buf;
|
|
return bytes_read;
|
|
}
|
|
|
|
long write_file(const char *file_name, unsigned char *data, long length)
|
|
{
|
|
FILE *out;
|
|
long bytes_written;
|
|
// open output file
|
|
out = fopen(file_name, "wb");
|
|
if (out == NULL) {
|
|
perror(file_name);
|
|
return -1;
|
|
}
|
|
bytes_written = fwrite(data, 1, length, out);
|
|
fclose(out);
|
|
return bytes_written;
|
|
}
|
|
|
|
void generate_filename(const char *in_name, char *out_name, char *extension)
|
|
{
|
|
char tmp_name[FILENAME_MAX];
|
|
int len;
|
|
int i;
|
|
strcpy(tmp_name, in_name);
|
|
len = strlen(tmp_name);
|
|
for (i = len - 1; i > 0; i--) {
|
|
if (tmp_name[i] == '.') {
|
|
break;
|
|
}
|
|
}
|
|
if (i <= 0) {
|
|
i = len;
|
|
}
|
|
tmp_name[i] = '\0';
|
|
sprintf(out_name, "%s.%s", tmp_name, extension);
|
|
}
|
|
|
|
char *basename(const char *name)
|
|
{
|
|
const char *base = name;
|
|
while (*name) {
|
|
if (*name++ == '/') {
|
|
base = name;
|
|
}
|
|
}
|
|
return (char *)base;
|
|
}
|
|
|
|
void make_dir(const char *dir_name)
|
|
{
|
|
struct stat st = {0};
|
|
if (stat(dir_name, &st) == -1) {
|
|
mkdir(dir_name, 0755);
|
|
}
|
|
}
|
|
|
|
long copy_file(const char *src_name, const char *dst_name)
|
|
{
|
|
unsigned char *buf;
|
|
long bytes_written;
|
|
long bytes_read;
|
|
|
|
bytes_read = read_file(src_name, &buf);
|
|
|
|
if (bytes_read > 0) {
|
|
bytes_written = write_file(dst_name, buf, bytes_read);
|
|
if (bytes_written != bytes_read) {
|
|
bytes_read = -1;
|
|
}
|
|
free(buf);
|
|
}
|
|
|
|
return bytes_read;
|
|
}
|
|
|
|
void dir_list_ext(const char *dir, const char *extension, dir_list *list)
|
|
{
|
|
char *pool;
|
|
char *pool_ptr;
|
|
struct dirent *entry;
|
|
DIR *dfd;
|
|
int idx;
|
|
|
|
dfd = opendir(dir);
|
|
if (dfd == NULL) {
|
|
ERROR("Can't open '%s'\n", dir);
|
|
exit(1);
|
|
}
|
|
|
|
pool = malloc(FILENAME_MAX * MAX_DIR_FILES);
|
|
pool_ptr = pool;
|
|
|
|
idx = 0;
|
|
while ((entry = readdir(dfd)) != NULL && idx < MAX_DIR_FILES) {
|
|
if (!extension || str_ends_with(entry->d_name, extension)) {
|
|
sprintf(pool_ptr, "%s/%s", dir, entry->d_name);
|
|
list->files[idx] = pool_ptr;
|
|
pool_ptr += strlen(pool_ptr) + 1;
|
|
idx++;
|
|
}
|
|
}
|
|
list->count = idx;
|
|
|
|
closedir(dfd);
|
|
}
|
|
|
|
void dir_list_free(dir_list *list)
|
|
{
|
|
// assume first entry in array is allocated
|
|
if (list->files[0]) {
|
|
free(list->files[0]);
|
|
list->files[0] = NULL;
|
|
}
|
|
}
|
|
|
|
int str_ends_with(const char *str, const char *suffix)
|
|
{
|
|
if (!str || !suffix) {
|
|
return 0;
|
|
}
|
|
size_t len_str = strlen(str);
|
|
size_t len_suffix = strlen(suffix);
|
|
if (len_suffix > len_str) {
|
|
return 0;
|
|
}
|
|
return (0 == strncmp(str + len_str - len_suffix, suffix, len_suffix));
|
|
}
|