obs-studio/libobs/util/file-serializer.c
2023-05-20 01:31:18 -07:00

187 lines
4 KiB
C

/*
* Copyright (c) 2023 Lain Bailey <lain@obsproject.com>
*
* 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 "dstr.h"
#include "file-serializer.h"
#include "platform.h"
static size_t file_input_read(void *file, void *data, size_t size)
{
return fread(data, 1, size, file);
}
static int64_t file_input_seek(void *file, int64_t offset,
enum serialize_seek_type seek_type)
{
int origin = SEEK_SET;
switch (seek_type) {
case SERIALIZE_SEEK_START:
origin = SEEK_SET;
break;
case SERIALIZE_SEEK_CURRENT:
origin = SEEK_CUR;
break;
case SERIALIZE_SEEK_END:
origin = SEEK_END;
break;
}
if (os_fseeki64(file, offset, origin) == -1)
return -1;
return os_ftelli64(file);
}
static int64_t file_input_get_pos(void *file)
{
return os_ftelli64(file);
}
bool file_input_serializer_init(struct serializer *s, const char *path)
{
s->data = os_fopen(path, "rb");
if (!s->data)
return false;
s->read = file_input_read;
s->write = NULL;
s->seek = file_input_seek;
s->get_pos = file_input_get_pos;
return true;
}
void file_input_serializer_free(struct serializer *s)
{
if (s->data)
fclose(s->data);
}
/* ------------------------------------------------------------------------- */
struct file_output_data {
FILE *file;
char *temp_name;
char *file_name;
};
static size_t file_output_write(void *sdata, const void *data, size_t size)
{
struct file_output_data *out = sdata;
return fwrite(data, 1, size, out->file);
}
static int64_t file_output_seek(void *sdata, int64_t offset,
enum serialize_seek_type seek_type)
{
struct file_output_data *out = sdata;
int origin = SEEK_SET;
switch (seek_type) {
case SERIALIZE_SEEK_START:
origin = SEEK_SET;
break;
case SERIALIZE_SEEK_CURRENT:
origin = SEEK_CUR;
break;
case SERIALIZE_SEEK_END:
origin = SEEK_END;
break;
}
if (os_fseeki64(out->file, offset, origin) == -1)
return -1;
return os_ftelli64(out->file);
}
static int64_t file_output_get_pos(void *sdata)
{
struct file_output_data *out = sdata;
return os_ftelli64(out->file);
}
bool file_output_serializer_init(struct serializer *s, const char *path)
{
FILE *file = os_fopen(path, "wb");
struct file_output_data *out;
if (!file)
return false;
out = bzalloc(sizeof(*out));
out->file = file;
s->data = out;
s->read = NULL;
s->write = file_output_write;
s->seek = file_output_seek;
s->get_pos = file_output_get_pos;
return true;
}
bool file_output_serializer_init_safe(struct serializer *s, const char *path,
const char *temp_ext)
{
struct dstr temp_name = {0};
struct file_output_data *out;
FILE *file;
if (!temp_ext || !*temp_ext)
return false;
dstr_copy(&temp_name, path);
if (*temp_ext != '.')
dstr_cat_ch(&temp_name, '.');
dstr_cat(&temp_name, temp_ext);
file = os_fopen(temp_name.array, "wb");
if (!file) {
dstr_free(&temp_name);
return false;
}
out = bzalloc(sizeof(*out));
out->file_name = bstrdup(path);
out->temp_name = temp_name.array;
out->file = file;
s->data = out;
s->read = NULL;
s->write = file_output_write;
s->seek = file_output_seek;
s->get_pos = file_output_get_pos;
return true;
}
void file_output_serializer_free(struct serializer *s)
{
struct file_output_data *out = s->data;
if (out) {
fclose(out->file);
if (out->temp_name) {
os_unlink(out->file_name);
os_rename(out->temp_name, out->file_name);
}
bfree(out->file_name);
bfree(out->temp_name);
bfree(out);
}
}