forked from Lephenixnoir/hex-editor
107 lines
2.2 KiB
C
107 lines
2.2 KiB
C
|
#include "source.h"
|
||
|
#include <string.h>
|
||
|
#include <stdlib.h>
|
||
|
#include <unistd.h>
|
||
|
#include <fcntl.h>
|
||
|
|
||
|
static void lf_free(loaded_file_t *lf)
|
||
|
{
|
||
|
if(lf) {
|
||
|
free(lf->path);
|
||
|
buffer_free(lf->buf);
|
||
|
}
|
||
|
free(lf);
|
||
|
}
|
||
|
|
||
|
static bool lf_read(void *_cookie, void *buf, off_t offset, size_t size)
|
||
|
{
|
||
|
loaded_file_t *lf = _cookie;
|
||
|
if(offset < 0 || offset + size > lf->buf->data_size)
|
||
|
return false;
|
||
|
|
||
|
memcpy(buf, lf->buf->mem + offset, size);
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
static bool lf_write(void *_cookie, void *data, size_t data_size, off_t offset,
|
||
|
size_t segment_size)
|
||
|
{
|
||
|
loaded_file_t *lf = _cookie;
|
||
|
return buffer_write(lf->buf, data, data_size, offset, segment_size);
|
||
|
}
|
||
|
|
||
|
static bool lf_save(void *_cookie)
|
||
|
{
|
||
|
loaded_file_t *lf = _cookie;
|
||
|
|
||
|
/* If the new file is larger than the original, we can just overwrite it
|
||
|
without truncating, which is much faster with Fugue */
|
||
|
int flags = O_WRONLY | O_TRUNC;
|
||
|
if(lf->buf->data_size >= lf->original_size)
|
||
|
flags = O_WRONLY;
|
||
|
int fd = open(lf->path, flags);
|
||
|
if(!fd) goto fail;
|
||
|
|
||
|
ssize_t rc = write(fd, lf->buf->mem, lf->buf->data_size);
|
||
|
if(rc < 0 || (size_t)rc != lf->buf->data_size) goto fail;
|
||
|
|
||
|
close(fd);
|
||
|
return true;
|
||
|
|
||
|
fail:
|
||
|
close(fd);
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
static void lf_close(void *_cookie)
|
||
|
{
|
||
|
loaded_file_t *lf = _cookie;
|
||
|
lf_free(lf);
|
||
|
}
|
||
|
|
||
|
static source_intf_t lf_intf = {
|
||
|
.cap = SOURCE_WRITE | SOURCE_EXPAND | SOURCE_SHRINK,
|
||
|
.read = lf_read,
|
||
|
.write = lf_write,
|
||
|
.save = lf_save,
|
||
|
.close = lf_close,
|
||
|
};
|
||
|
|
||
|
source_t *source_loaded_file_open(char const *path)
|
||
|
{
|
||
|
int fd = -1;
|
||
|
source_t *source = NULL;
|
||
|
loaded_file_t *lf = NULL;
|
||
|
|
||
|
lf = calloc(1, sizeof *lf);
|
||
|
if(!lf) goto fail;
|
||
|
|
||
|
lf->path = strdup(path);
|
||
|
if(!lf->path) goto fail;
|
||
|
|
||
|
fd = open(path, O_RDONLY);
|
||
|
if(fd < 0) goto fail;
|
||
|
|
||
|
int size = lseek(fd, 0, SEEK_END);
|
||
|
if(size < 0) goto fail;
|
||
|
|
||
|
lf->original_size = size;
|
||
|
lf->buf = buffer_create(size, 4096);
|
||
|
if(!lf->buf) goto fail;
|
||
|
|
||
|
ssize_t rc = pread(fd, lf->buf->mem, size, 0);
|
||
|
if(rc != size) goto fail;
|
||
|
|
||
|
source = source_open(&lf_intf, lf);
|
||
|
if(!source) goto fail;
|
||
|
|
||
|
close(fd);
|
||
|
return source;
|
||
|
|
||
|
fail:
|
||
|
free(source);
|
||
|
close(fd);
|
||
|
lf_free(lf);
|
||
|
return NULL;
|
||
|
}
|