mirror of
https://github.com/libretro/libretro-common.git
synced 2025-02-25 19:20:39 +00:00
Updates
This commit is contained in:
parent
db2e701cfe
commit
06b9b3790a
@ -289,26 +289,26 @@ static void arm_enable_runfast_mode(void)
|
||||
#if defined(__linux__) && !defined(CPU_X86)
|
||||
static unsigned char check_arm_cpu_feature(const char* feature)
|
||||
{
|
||||
char line[1024];
|
||||
unsigned char status = 0;
|
||||
FILE *fp = fopen("/proc/cpuinfo", "r");
|
||||
RFILE *fp = filestream_open("/proc/cpuinfo", RFILE_MODE_READ_TEXT, -1);
|
||||
|
||||
if (fp)
|
||||
if (!fp)
|
||||
return 0;
|
||||
|
||||
while (filestream_gets(fp, line, sizeof(line)) != NULL)
|
||||
{
|
||||
char line[1024];
|
||||
if (strncmp(line, "Features\t: ", 11))
|
||||
continue;
|
||||
|
||||
while (fgets(line , sizeof(line) , fp) != NULL)
|
||||
{
|
||||
if (strncmp(line, "Features\t: ", 11))
|
||||
continue;
|
||||
if (strstr(line + 11, feature) != NULL)
|
||||
status = 1;
|
||||
|
||||
if (strstr(line + 11, feature) != NULL)
|
||||
status = 1;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
break;
|
||||
}
|
||||
|
||||
filestream_close(fp);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
@ -451,7 +451,7 @@ static int file_archive_decompress_data_to_file(
|
||||
}
|
||||
|
||||
end:
|
||||
if (handle->data)
|
||||
if (handle && handle->data)
|
||||
free(handle->data);
|
||||
return ret;
|
||||
}
|
||||
|
@ -76,12 +76,12 @@ struct config_file
|
||||
struct config_include_list *includes;
|
||||
};
|
||||
|
||||
static config_file_t *config_file_new_internal(const char *path, unsigned depth);
|
||||
void config_file_free(config_file_t *conf);
|
||||
static config_file_t *config_file_new_internal(
|
||||
const char *path, unsigned depth);
|
||||
|
||||
static char *getaline(FILE *file)
|
||||
{
|
||||
char* newline = (char*)malloc(9);
|
||||
char* newline = (char*)malloc(9);
|
||||
char* newline_tmp = NULL;
|
||||
size_t cur_size = 8;
|
||||
size_t idx = 0;
|
||||
@ -113,6 +113,45 @@ static char *getaline(FILE *file)
|
||||
return newline;
|
||||
}
|
||||
|
||||
static char *strip_comment(char *str)
|
||||
{
|
||||
/* Remove everything after comment.
|
||||
* Keep #s inside string literals. */
|
||||
char *string_end = str + strlen(str);
|
||||
bool cut_comment = true;
|
||||
|
||||
while (!string_is_empty(str))
|
||||
{
|
||||
char *comment = NULL;
|
||||
char *literal = strchr(str, '\"');
|
||||
if (!literal)
|
||||
literal = string_end;
|
||||
comment = (char*)strchr(str, '#');
|
||||
if (!comment)
|
||||
comment = string_end;
|
||||
|
||||
if (cut_comment && literal < comment)
|
||||
{
|
||||
cut_comment = false;
|
||||
str = literal + 1;
|
||||
}
|
||||
else if (!cut_comment && literal)
|
||||
{
|
||||
cut_comment = true;
|
||||
str = literal + 1;
|
||||
}
|
||||
else if (comment)
|
||||
{
|
||||
*comment = '\0';
|
||||
str = comment;
|
||||
}
|
||||
else
|
||||
str = string_end;
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
static char *extract_value(char *line, bool is_value)
|
||||
{
|
||||
char *save = NULL;
|
||||
@ -153,6 +192,27 @@ static char *extract_value(char *line, bool is_value)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void add_include_list(config_file_t *conf, const char *path)
|
||||
{
|
||||
struct config_include_list *head = conf->includes;
|
||||
struct config_include_list *node = (struct config_include_list*)calloc(1, sizeof(*node));
|
||||
|
||||
if (!node)
|
||||
return;
|
||||
|
||||
node->path = strdup(path);
|
||||
|
||||
if (head)
|
||||
{
|
||||
while (head->next)
|
||||
head = head->next;
|
||||
|
||||
head->next = node;
|
||||
}
|
||||
else
|
||||
conf->includes = node;
|
||||
}
|
||||
|
||||
static void set_list_readonly(struct config_entry_list *list)
|
||||
{
|
||||
while (list)
|
||||
@ -196,27 +256,6 @@ static void add_child_list(config_file_t *parent, config_file_t *child)
|
||||
parent->tail = NULL;
|
||||
}
|
||||
|
||||
static void add_include_list(config_file_t *conf, const char *path)
|
||||
{
|
||||
struct config_include_list *head = conf->includes;
|
||||
struct config_include_list *node = (struct config_include_list*)calloc(1, sizeof(*node));
|
||||
|
||||
if (!node)
|
||||
return;
|
||||
|
||||
node->path = strdup(path);
|
||||
|
||||
if (head)
|
||||
{
|
||||
while (head->next)
|
||||
head = head->next;
|
||||
|
||||
head->next = node;
|
||||
}
|
||||
else
|
||||
conf->includes = node;
|
||||
}
|
||||
|
||||
static void add_sub_conf(config_file_t *conf, char *line)
|
||||
{
|
||||
char real_path[PATH_MAX_LENGTH] = {0};
|
||||
@ -259,45 +298,6 @@ static void add_sub_conf(config_file_t *conf, char *line)
|
||||
free(path);
|
||||
}
|
||||
|
||||
static char *strip_comment(char *str)
|
||||
{
|
||||
/* Remove everything after comment.
|
||||
* Keep #s inside string literals. */
|
||||
char *strend = str + strlen(str);
|
||||
bool cut_comment = true;
|
||||
|
||||
while (!string_is_empty(str))
|
||||
{
|
||||
char *comment = NULL;
|
||||
char *literal = strchr(str, '\"');
|
||||
if (!literal)
|
||||
literal = strend;
|
||||
comment = (char*)strchr(str, '#');
|
||||
if (!comment)
|
||||
comment = strend;
|
||||
|
||||
if (cut_comment && literal < comment)
|
||||
{
|
||||
cut_comment = false;
|
||||
str = literal + 1;
|
||||
}
|
||||
else if (!cut_comment && literal)
|
||||
{
|
||||
cut_comment = true;
|
||||
str = literal + 1;
|
||||
}
|
||||
else if (comment)
|
||||
{
|
||||
*comment = '\0';
|
||||
str = comment;
|
||||
}
|
||||
else
|
||||
str = strend;
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
static bool parse_line(config_file_t *conf,
|
||||
struct config_entry_list *list, char *line)
|
||||
{
|
||||
@ -371,23 +371,6 @@ static bool parse_line(config_file_t *conf,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool config_append_file(config_file_t *conf, const char *path)
|
||||
{
|
||||
config_file_t *new_conf = config_file_new(path);
|
||||
if (!new_conf)
|
||||
return false;
|
||||
|
||||
if (new_conf->tail)
|
||||
{
|
||||
new_conf->tail->next = conf->entries;
|
||||
conf->entries = new_conf->entries; /* Pilfer. */
|
||||
new_conf->entries = NULL;
|
||||
}
|
||||
|
||||
config_file_free(new_conf);
|
||||
return true;
|
||||
}
|
||||
|
||||
static config_file_t *config_file_new_internal(
|
||||
const char *path, unsigned depth)
|
||||
{
|
||||
@ -430,26 +413,24 @@ static config_file_t *config_file_new_internal(
|
||||
|
||||
line = getaline(file);
|
||||
|
||||
if (line)
|
||||
{
|
||||
if (parse_line(conf, list, line))
|
||||
{
|
||||
if (conf->entries)
|
||||
conf->tail->next = list;
|
||||
else
|
||||
conf->entries = list;
|
||||
|
||||
conf->tail = list;
|
||||
}
|
||||
|
||||
free(line);
|
||||
}
|
||||
else
|
||||
if (!line)
|
||||
{
|
||||
free(list);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (parse_line(conf, list, line))
|
||||
{
|
||||
if (conf->entries)
|
||||
conf->tail->next = list;
|
||||
else
|
||||
conf->entries = list;
|
||||
|
||||
conf->tail = list;
|
||||
}
|
||||
|
||||
free(line);
|
||||
|
||||
if (list != conf->tail)
|
||||
free(list);
|
||||
}
|
||||
@ -464,6 +445,65 @@ error:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void config_file_free(config_file_t *conf)
|
||||
{
|
||||
struct config_include_list *inc_tmp = NULL;
|
||||
struct config_entry_list *tmp = NULL;
|
||||
if (!conf)
|
||||
return;
|
||||
|
||||
tmp = conf->entries;
|
||||
while (tmp)
|
||||
{
|
||||
struct config_entry_list *hold = NULL;
|
||||
if (tmp->key)
|
||||
free(tmp->key);
|
||||
if (tmp->value)
|
||||
free(tmp->value);
|
||||
|
||||
tmp->value = NULL;
|
||||
tmp->key = NULL;
|
||||
|
||||
hold = tmp;
|
||||
tmp = tmp->next;
|
||||
|
||||
if (hold)
|
||||
free(hold);
|
||||
}
|
||||
|
||||
inc_tmp = (struct config_include_list*)conf->includes;
|
||||
while (inc_tmp)
|
||||
{
|
||||
struct config_include_list *hold = NULL;
|
||||
free(inc_tmp->path);
|
||||
hold = (struct config_include_list*)inc_tmp;
|
||||
inc_tmp = inc_tmp->next;
|
||||
free(hold);
|
||||
}
|
||||
|
||||
if (conf->path)
|
||||
free(conf->path);
|
||||
free(conf);
|
||||
}
|
||||
|
||||
bool config_append_file(config_file_t *conf, const char *path)
|
||||
{
|
||||
config_file_t *new_conf = config_file_new(path);
|
||||
if (!new_conf)
|
||||
return false;
|
||||
|
||||
if (new_conf->tail)
|
||||
{
|
||||
new_conf->tail->next = conf->entries;
|
||||
conf->entries = new_conf->entries; /* Pilfer. */
|
||||
new_conf->entries = NULL;
|
||||
}
|
||||
|
||||
config_file_free(new_conf);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
config_file_t *config_file_new_from_string(const char *from_string)
|
||||
{
|
||||
size_t i;
|
||||
@ -522,46 +562,6 @@ config_file_t *config_file_new(const char *path)
|
||||
return config_file_new_internal(path, 0);
|
||||
}
|
||||
|
||||
void config_file_free(config_file_t *conf)
|
||||
{
|
||||
struct config_include_list *inc_tmp = NULL;
|
||||
struct config_entry_list *tmp = NULL;
|
||||
if (!conf)
|
||||
return;
|
||||
|
||||
tmp = conf->entries;
|
||||
while (tmp)
|
||||
{
|
||||
struct config_entry_list *hold = NULL;
|
||||
if (tmp->key)
|
||||
free(tmp->key);
|
||||
if (tmp->value)
|
||||
free(tmp->value);
|
||||
|
||||
tmp->value = NULL;
|
||||
tmp->key = NULL;
|
||||
|
||||
hold = tmp;
|
||||
tmp = tmp->next;
|
||||
|
||||
if (hold)
|
||||
free(hold);
|
||||
}
|
||||
|
||||
inc_tmp = (struct config_include_list*)conf->includes;
|
||||
while (inc_tmp)
|
||||
{
|
||||
struct config_include_list *hold = NULL;
|
||||
free(inc_tmp->path);
|
||||
hold = (struct config_include_list*)inc_tmp;
|
||||
inc_tmp = inc_tmp->next;
|
||||
free(hold);
|
||||
}
|
||||
|
||||
if (conf->path)
|
||||
free(conf->path);
|
||||
free(conf);
|
||||
}
|
||||
|
||||
static struct config_entry_list *config_get_entry(const config_file_t *conf,
|
||||
const char *key, struct config_entry_list **prev)
|
||||
|
@ -61,6 +61,7 @@ enum png_chunk_type
|
||||
PNG_CHUNK_IHDR,
|
||||
PNG_CHUNK_IDAT,
|
||||
PNG_CHUNK_PLTE,
|
||||
PNG_CHUNK_tRNS,
|
||||
PNG_CHUNK_IEND
|
||||
};
|
||||
|
||||
@ -121,6 +122,7 @@ struct rpng
|
||||
bool has_idat;
|
||||
bool has_iend;
|
||||
bool has_plte;
|
||||
bool has_trns;
|
||||
struct idat_buffer idat_buf;
|
||||
struct png_ihdr ihdr;
|
||||
uint8_t *buff_data;
|
||||
@ -144,6 +146,7 @@ static enum png_chunk_type png_chunk_type(const struct png_chunk *chunk)
|
||||
{ "IDAT", PNG_CHUNK_IDAT },
|
||||
{ "IEND", PNG_CHUNK_IEND },
|
||||
{ "PLTE", PNG_CHUNK_PLTE },
|
||||
{ "tRNS", PNG_CHUNK_tRNS },
|
||||
};
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(chunk_map); i++)
|
||||
@ -324,18 +327,100 @@ static void png_reverse_filter_copy_line_plt(uint32_t *data,
|
||||
const uint8_t *decoded, unsigned width,
|
||||
unsigned depth, const uint32_t *palette)
|
||||
{
|
||||
unsigned i, bit;
|
||||
unsigned mask = (1 << depth) - 1;
|
||||
|
||||
bit = 0;
|
||||
|
||||
for (i = 0; i < width; i++, bit += depth)
|
||||
switch (depth)
|
||||
{
|
||||
unsigned byte = bit >> 3;
|
||||
unsigned val = decoded[byte] >> (8 - depth - (bit & 7));
|
||||
|
||||
val &= mask;
|
||||
data[i] = palette[val];
|
||||
case 1:
|
||||
{
|
||||
unsigned w = width / 8;
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < w; i++, decoded++)
|
||||
{
|
||||
*data++ = palette[(*decoded >> 7) & 1];
|
||||
*data++ = palette[(*decoded >> 6) & 1];
|
||||
*data++ = palette[(*decoded >> 5) & 1];
|
||||
*data++ = palette[(*decoded >> 4) & 1];
|
||||
*data++ = palette[(*decoded >> 3) & 1];
|
||||
*data++ = palette[(*decoded >> 2) & 1];
|
||||
*data++ = palette[(*decoded >> 1) & 1];
|
||||
*data++ = palette[*decoded & 1];
|
||||
}
|
||||
|
||||
switch (width & 7)
|
||||
{
|
||||
case 7:
|
||||
data[6] = palette[(*decoded >> 1) & 1];
|
||||
case 6:
|
||||
data[5] = palette[(*decoded >> 2) & 1];
|
||||
case 5:
|
||||
data[4] = palette[(*decoded >> 3) & 1];
|
||||
case 4:
|
||||
data[3] = palette[(*decoded >> 4) & 1];
|
||||
case 3:
|
||||
data[2] = palette[(*decoded >> 5) & 1];
|
||||
case 2:
|
||||
data[1] = palette[(*decoded >> 6) & 1];
|
||||
case 1:
|
||||
data[0] = palette[(*decoded >> 7) & 1];
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 2:
|
||||
{
|
||||
unsigned w = width / 4;
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < w; i++, decoded++)
|
||||
{
|
||||
*data++ = palette[(*decoded >> 6) & 3];
|
||||
*data++ = palette[(*decoded >> 4) & 3];
|
||||
*data++ = palette[(*decoded >> 2) & 3];
|
||||
*data++ = palette[*decoded & 3];
|
||||
}
|
||||
|
||||
switch (width & 3)
|
||||
{
|
||||
case 3:
|
||||
data[2] = palette[(*decoded >> 2) & 3];
|
||||
case 2:
|
||||
data[1] = palette[(*decoded >> 4) & 3];
|
||||
case 1:
|
||||
data[0] = palette[(*decoded >> 6) & 3];
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 4:
|
||||
{
|
||||
unsigned w = width / 2;
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < w; i++, decoded++)
|
||||
{
|
||||
*data++ = palette[*decoded >> 4];
|
||||
*data++ = palette[*decoded & 0x0f];
|
||||
}
|
||||
|
||||
if (width & 1)
|
||||
{
|
||||
*data = palette[*decoded >> 4];
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 8:
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < width; i++, decoded++, data++)
|
||||
{
|
||||
*data = palette[*decoded];
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -754,6 +839,18 @@ static bool png_read_plte(uint8_t *buf,
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool png_read_trns(uint8_t *buf, uint32_t *palette, unsigned entries)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < entries; i++, buf++, palette++)
|
||||
{
|
||||
*palette = (*palette & 0x00ffffff) | *buf << 24;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool png_realloc_idat(const struct png_chunk *chunk, struct idat_buffer *buf)
|
||||
{
|
||||
uint8_t *new_buffer = (uint8_t*)realloc(buf->data, buf->size + chunk->size);
|
||||
@ -900,7 +997,7 @@ bool rpng_iterate_image(rpng_t *rpng)
|
||||
{
|
||||
unsigned entries = chunk.size / 3;
|
||||
|
||||
if (!rpng->has_ihdr || rpng->has_plte || rpng->has_iend || rpng->has_idat)
|
||||
if (!rpng->has_ihdr || rpng->has_plte || rpng->has_iend || rpng->has_idat || rpng->has_trns)
|
||||
goto error;
|
||||
|
||||
if (chunk.size % 3)
|
||||
@ -918,6 +1015,26 @@ bool rpng_iterate_image(rpng_t *rpng)
|
||||
}
|
||||
break;
|
||||
|
||||
case PNG_CHUNK_tRNS:
|
||||
if (rpng->has_idat)
|
||||
goto error;
|
||||
|
||||
if (rpng->ihdr.color_type == PNG_IHDR_COLOR_PLT)
|
||||
{
|
||||
/* we should compare with the number of palette entries */
|
||||
if (chunk.size > 256)
|
||||
goto error;
|
||||
|
||||
buf += 8;
|
||||
|
||||
if (!png_read_trns(buf, rpng->palette, chunk.size))
|
||||
goto error;
|
||||
}
|
||||
/* TODO: support colorkey in grayscale and truecolor images */
|
||||
|
||||
rpng->has_trns = true;
|
||||
break;
|
||||
|
||||
case PNG_CHUNK_IDAT:
|
||||
if (!(rpng->has_ihdr) || rpng->has_iend || (rpng->ihdr.color_type == PNG_IHDR_COLOR_PLT && !(rpng->has_plte)))
|
||||
goto error;
|
||||
|
@ -367,7 +367,8 @@ end:
|
||||
free(avg_filtered);
|
||||
free(paeth_filtered);
|
||||
|
||||
stream_backend->stream_free(stream);
|
||||
if (stream_backend)
|
||||
stream_backend->stream_free(stream);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -256,6 +256,10 @@ static uint8_t *rtga__tga_load(rtga__context *s, unsigned *x, unsigned *y, int *
|
||||
int RLE_count = 0;
|
||||
int RLE_repeating = 0;
|
||||
int read_next_pixel = 1;
|
||||
|
||||
(void)tga_palette_start;
|
||||
(void)tga_x_origin;
|
||||
(void)tga_y_origin;
|
||||
|
||||
/* do a tiny bit of precessing */
|
||||
if ( tga_image_type >= 8 )
|
||||
@ -417,9 +421,6 @@ static uint8_t *rtga__tga_load(rtga__context *s, unsigned *x, unsigned *y, int *
|
||||
if (req_comp && req_comp != tga_comp)
|
||||
tga_data = rtga__convert_format(tga_data, tga_comp, req_comp, tga_width, tga_height);
|
||||
|
||||
tga_palette_start = tga_palette_len = tga_palette_bits =
|
||||
tga_x_origin = tga_y_origin = 0;
|
||||
|
||||
return tga_data;
|
||||
}
|
||||
|
||||
|
@ -38,6 +38,7 @@ typedef struct RFILE RFILE;
|
||||
enum
|
||||
{
|
||||
RFILE_MODE_READ = 0,
|
||||
RFILE_MODE_READ_TEXT,
|
||||
RFILE_MODE_WRITE,
|
||||
RFILE_MODE_READ_WRITE,
|
||||
|
||||
@ -62,6 +63,14 @@ int filestream_close(RFILE *stream);
|
||||
|
||||
int filestream_read_file(const char *path, void **buf, ssize_t *len);
|
||||
|
||||
char *filestream_gets(RFILE *stream, char *s, size_t len);
|
||||
|
||||
char *filestream_getline(RFILE *stream);
|
||||
|
||||
int filestream_getc(RFILE *stream);
|
||||
|
||||
int filestream_eof(RFILE *stream);
|
||||
|
||||
bool filestream_write_file(const char *path, const void *data, ssize_t size);
|
||||
|
||||
int filestream_putc(RFILE *stream, int c);
|
||||
|
@ -89,7 +89,7 @@ bool file_list_prepend(file_list_t *list,
|
||||
free(copy);
|
||||
}
|
||||
|
||||
memset(&list->list[0], 0, sizeof(file_list_t));
|
||||
memset(&list->list[0], 0, sizeof(*list->list) * list->capacity);
|
||||
|
||||
list->list[0].label = NULL;
|
||||
list->list[0].path = NULL;
|
||||
|
@ -215,42 +215,45 @@ static bool retro_task_regular_find(retro_task_finder_t func, void *user_data)
|
||||
|
||||
static void retro_task_regular_retrieve(task_retriever_data_t *data)
|
||||
{
|
||||
retro_task_t *task;
|
||||
task_retriever_info_t *info;
|
||||
retro_task_t *task = NULL;
|
||||
task_retriever_info_t *tail = NULL;
|
||||
|
||||
/* Parse all running tasks and handle matching handlers */
|
||||
for (task = tasks_running.front; task != NULL; task = task->next)
|
||||
if (task->handler == data->handler)
|
||||
{
|
||||
task_retriever_info_t *info = NULL;
|
||||
if (task->handler != data->handler)
|
||||
continue;
|
||||
|
||||
/* Create new link */
|
||||
info = (task_retriever_info_t*)malloc(sizeof(task_retriever_info_t));
|
||||
info->data = malloc(data->element_size);
|
||||
info->next = NULL;
|
||||
|
||||
/* Call retriever function and fill info-specific data */
|
||||
if (!data->func(task, info->data))
|
||||
{
|
||||
/* Create new link */
|
||||
info = (task_retriever_info_t*)malloc(sizeof(task_retriever_info_t));
|
||||
info->data = malloc(data->element_size);
|
||||
info->next = NULL;
|
||||
|
||||
/* Call retriever function and fill info-specific data */
|
||||
if (!data->func(task, info->data))
|
||||
{
|
||||
free(info->data);
|
||||
free(info);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Add link to list */
|
||||
if (data->list == NULL)
|
||||
{
|
||||
data->list = info;
|
||||
tail = data->list;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (tail)
|
||||
{
|
||||
tail->next = info;
|
||||
tail = tail->next;
|
||||
}
|
||||
}
|
||||
free(info->data);
|
||||
free(info);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Add link to list */
|
||||
if (data->list)
|
||||
{
|
||||
if (tail)
|
||||
{
|
||||
tail->next = info;
|
||||
tail = tail->next;
|
||||
}
|
||||
free(info);
|
||||
}
|
||||
else
|
||||
{
|
||||
data->list = info;
|
||||
tail = data->list;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static struct retro_task_impl impl_regular = {
|
||||
|
@ -129,6 +129,19 @@ RFILE *filestream_open(const char *path, unsigned mode, ssize_t len)
|
||||
|
||||
switch (mode & 0xff)
|
||||
{
|
||||
case RFILE_MODE_READ_TEXT:
|
||||
#if defined(VITA) || defined(PSP)
|
||||
mode_int = 0777;
|
||||
flags = PSP_O_RDONLY;
|
||||
#else
|
||||
#if defined(HAVE_BUFFERED_IO)
|
||||
if ((stream->hints & RFILE_HINT_UNBUFFERED) == 0)
|
||||
mode_str = "r";
|
||||
#endif
|
||||
/* No "else" here */
|
||||
flags = O_RDONLY;
|
||||
#endif
|
||||
break;
|
||||
case RFILE_MODE_READ:
|
||||
#if defined(VITA) || defined(PSP)
|
||||
mode_int = 0777;
|
||||
@ -230,6 +243,63 @@ error:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *filestream_getline(RFILE *stream)
|
||||
{
|
||||
char* newline = (char*)malloc(9);
|
||||
char* newline_tmp = NULL;
|
||||
size_t cur_size = 8;
|
||||
size_t idx = 0;
|
||||
int in = filestream_getc(stream);
|
||||
|
||||
if (!newline)
|
||||
return NULL;
|
||||
|
||||
while (in != EOF && in != '\n')
|
||||
{
|
||||
if (idx == cur_size)
|
||||
{
|
||||
cur_size *= 2;
|
||||
newline_tmp = (char*)realloc(newline, cur_size + 1);
|
||||
|
||||
if (!newline_tmp)
|
||||
{
|
||||
free(newline);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
newline = newline_tmp;
|
||||
}
|
||||
|
||||
newline[idx++] = in;
|
||||
in = filestream_getc(stream);
|
||||
}
|
||||
|
||||
newline[idx] = '\0';
|
||||
return newline;
|
||||
}
|
||||
|
||||
char *filestream_gets(RFILE *stream, char *s, size_t len)
|
||||
{
|
||||
if (!stream)
|
||||
return NULL;
|
||||
#if defined(HAVE_BUFFERED_IO)
|
||||
return fgets(s, len, stream->fp);
|
||||
#else
|
||||
return gets(s);
|
||||
#endif
|
||||
}
|
||||
|
||||
int filestream_getc(RFILE *stream)
|
||||
{
|
||||
if (!stream)
|
||||
return 0;
|
||||
#if defined(HAVE_BUFFERED_IO)
|
||||
return fgetc(stream->fp);
|
||||
#else
|
||||
return getc(stream->fp);
|
||||
#endif
|
||||
}
|
||||
|
||||
ssize_t filestream_seek(RFILE *stream, ssize_t offset, int whence)
|
||||
{
|
||||
if (!stream)
|
||||
@ -291,6 +361,18 @@ error:
|
||||
return -1;
|
||||
}
|
||||
|
||||
int filestream_eof(RFILE *stream)
|
||||
{
|
||||
ssize_t current_position = filestream_tell(stream);
|
||||
ssize_t end_position = filestream_seek(stream, 0, SEEK_END);
|
||||
|
||||
filestream_seek(stream, current_position, SEEK_SET);
|
||||
|
||||
if (current_position >= end_position)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
ssize_t filestream_tell(RFILE *stream)
|
||||
{
|
||||
if (!stream)
|
||||
|
@ -198,8 +198,7 @@ char *intfstream_gets(intfstream_internal_t *intf,
|
||||
switch (intf->type)
|
||||
{
|
||||
case INTFSTREAM_FILE:
|
||||
/* unimplemented */
|
||||
break;
|
||||
return filestream_gets(intf->file.fp, buffer, len);
|
||||
case INTFSTREAM_MEMORY:
|
||||
return memstream_gets(intf->memory.fp, buffer, len);
|
||||
}
|
||||
@ -215,8 +214,7 @@ int intfstream_getc(intfstream_internal_t *intf)
|
||||
switch (intf->type)
|
||||
{
|
||||
case INTFSTREAM_FILE:
|
||||
/* unimplemented */
|
||||
break;
|
||||
return filestream_getc(intf->file.fp);
|
||||
case INTFSTREAM_MEMORY:
|
||||
return memstream_getc(intf->memory.fp);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user