277 lines
5.1 KiB
C
277 lines
5.1 KiB
C
#include "nx/nxdata.h"
|
|
#include "foundation/atomics.h"
|
|
#include "foundation/error.h"
|
|
#include "nx/nxfile.h"
|
|
#include <sys/stat.h>
|
|
|
|
/* windows implementation */
|
|
struct nx_data_struct_t
|
|
{
|
|
volatile size_t ref_count;
|
|
nx_string_t mime_type;
|
|
nx_string_t description;
|
|
nx_uri_t source_uri;
|
|
nx_file_stat_t source_stats;
|
|
size_t len;
|
|
uint8_t data[1];
|
|
};
|
|
|
|
static size_t NXDataMallocSize(size_t bytes)
|
|
{
|
|
/* TODO: overflow check? */
|
|
const nx_data_t dummy=0;
|
|
size_t header = (size_t)&dummy->data[0] - (size_t)dummy;
|
|
return header + bytes;
|
|
}
|
|
|
|
nx_data_t NXDataRetain(nx_data_t data)
|
|
{
|
|
if (!data)
|
|
return 0;
|
|
|
|
nx_atomic_inc(&data->ref_count);
|
|
return data;
|
|
}
|
|
|
|
void NXDataRelease(nx_data_t data)
|
|
{
|
|
if (data)
|
|
{
|
|
if (nx_atomic_dec(&data->ref_count) == 0)
|
|
{
|
|
free(data->source_stats);
|
|
NXURIRelease(data->source_uri);
|
|
NXStringRelease(data->mime_type);
|
|
NXStringRelease(data->description);
|
|
free(data);
|
|
}
|
|
}
|
|
}
|
|
|
|
int NXDataCreate(nx_data_t *out_data, const void *bytes, size_t length)
|
|
{
|
|
void *new_bytes;
|
|
int ret = NXDataCreateWithSize(out_data, &new_bytes, length);
|
|
if (ret != NErr_Success)
|
|
return ret;
|
|
|
|
memcpy(new_bytes, bytes, length);
|
|
return NErr_Success;
|
|
}
|
|
|
|
int NXDataCreateWithSize(nx_data_t *out_data, void **bytes, size_t length)
|
|
{
|
|
nx_data_t data = 0;
|
|
size_t data_length = NXDataMallocSize(length);
|
|
data = (nx_data_t)malloc(data_length);
|
|
if (!data)
|
|
return NErr_OutOfMemory;
|
|
|
|
data->ref_count = 1;
|
|
data->len = length;
|
|
data->mime_type=0;
|
|
data->source_uri=0;
|
|
data->source_stats=0;
|
|
data->description=0;
|
|
if (bytes)
|
|
*bytes = data->data;
|
|
*out_data=data;
|
|
return NErr_Success;
|
|
}
|
|
|
|
int NXDataCreateEmpty(nx_data_t *out_data)
|
|
{
|
|
return NXDataCreateWithSize(out_data, 0, 0);
|
|
}
|
|
|
|
int NXDataCreateFromURI(nx_data_t *out_data, nx_uri_t filename)
|
|
{
|
|
nx_file_stat_s stat_buffer;
|
|
nx_data_t data;
|
|
size_t data_length;
|
|
size_t bytes_read;
|
|
uint64_t file_length;
|
|
void *bytes;
|
|
int ret;
|
|
int fd;
|
|
|
|
|
|
fd = NXFile_open(filename, nx_file_O_BINARY|nx_file_O_RDONLY);
|
|
if (fd == -1)
|
|
return NErr_FileNotFound;
|
|
|
|
ret = NXFile_fstat(fd, &stat_buffer);
|
|
if (ret != NErr_Success)
|
|
{
|
|
close(fd);
|
|
return ret;
|
|
}
|
|
|
|
file_length = stat_buffer.file_size;
|
|
|
|
if (file_length > SIZE_MAX)
|
|
{
|
|
close(fd);
|
|
return NErr_IntegerOverflow;
|
|
}
|
|
|
|
data_length = (size_t)file_length;
|
|
|
|
ret = NXDataCreateWithSize(&data, &bytes, data_length);
|
|
if (ret != NErr_Success)
|
|
{
|
|
close(fd);
|
|
return ret;
|
|
}
|
|
|
|
data->source_stats=(nx_file_stat_t)malloc(sizeof(nx_file_stat_s));
|
|
if (!data->source_stats)
|
|
{
|
|
close(fd);
|
|
NXDataRelease(data);
|
|
return NErr_OutOfMemory;
|
|
}
|
|
|
|
bytes_read = read(fd, bytes, (int)data_length);
|
|
close(fd);
|
|
if (bytes_read != data_length)
|
|
{
|
|
NXDataRelease(data);
|
|
return NErr_Error;
|
|
}
|
|
|
|
*data->source_stats=stat_buffer;
|
|
data->source_uri=NXURIRetain(filename);
|
|
*out_data = data;
|
|
return NErr_Success;
|
|
}
|
|
|
|
int NXDataGet(nx_data_t data, const void **bytes, size_t *length)
|
|
{
|
|
if (!data)
|
|
return NErr_BadParameter;
|
|
|
|
if (data->len == 0)
|
|
return NErr_Empty;
|
|
|
|
*bytes = data->data;
|
|
*length = data->len;
|
|
return NErr_Success;
|
|
}
|
|
|
|
size_t NXDataSize(nx_data_t data)
|
|
{
|
|
if (!data)
|
|
return 0;
|
|
|
|
return data->len;
|
|
}
|
|
|
|
int NXDataSetMIME(nx_data_t data, nx_string_t mime_type)
|
|
{
|
|
nx_string_t old;
|
|
if (!data)
|
|
return NErr_BadParameter;
|
|
|
|
old = data->mime_type;
|
|
data->mime_type = NXStringRetain(mime_type);
|
|
NXStringRelease(old);
|
|
return NErr_Success;
|
|
}
|
|
|
|
int NXDataSetDescription(nx_data_t data, nx_string_t description)
|
|
{
|
|
nx_string_t old;
|
|
if (!data)
|
|
return NErr_BadParameter;
|
|
|
|
old = data->description;
|
|
data->description = NXStringRetain(description);
|
|
NXStringRelease(old);
|
|
return NErr_Success;
|
|
}
|
|
|
|
int NXDataSetSourceURI(nx_data_t data, nx_uri_t source_uri)
|
|
{
|
|
nx_uri_t old;
|
|
if (!data)
|
|
return NErr_BadParameter;
|
|
|
|
old = data->source_uri;
|
|
data->source_uri = NXURIRetain(source_uri);
|
|
NXURIRelease(old);
|
|
return NErr_Success;
|
|
}
|
|
|
|
int NXDataSetSourceStat(nx_data_t data, nx_file_stat_t source_stats)
|
|
{
|
|
nx_file_stat_t new_stats;
|
|
if (!data)
|
|
return NErr_BadParameter;
|
|
|
|
if (source_stats)
|
|
{
|
|
new_stats=(nx_file_stat_t)malloc(sizeof(nx_file_stat_s));
|
|
if (!new_stats)
|
|
return NErr_OutOfMemory;
|
|
|
|
*new_stats = *source_stats;
|
|
free(data->source_stats);
|
|
data->source_stats=new_stats;
|
|
}
|
|
else
|
|
{
|
|
free(data->source_stats);
|
|
data->source_stats=0;
|
|
}
|
|
return NErr_Success;
|
|
}
|
|
|
|
int NXDataGetMIME(nx_data_t data, nx_string_t *mime_type)
|
|
{
|
|
if (!data)
|
|
return NErr_BadParameter;
|
|
|
|
if (!data->mime_type)
|
|
return NErr_Empty;
|
|
|
|
*mime_type = NXStringRetain(data->mime_type);
|
|
return NErr_Success;
|
|
}
|
|
|
|
int NXDataGetDescription(nx_data_t data, nx_string_t *description)
|
|
{
|
|
if (!data)
|
|
return NErr_BadParameter;
|
|
|
|
if (!data->description)
|
|
return NErr_Empty;
|
|
|
|
*description = NXStringRetain(data->description);
|
|
return NErr_Success;
|
|
}
|
|
|
|
int NXDataGetSourceURI(nx_data_t data, nx_uri_t *source_uri)
|
|
{
|
|
if (!data)
|
|
return NErr_BadParameter;
|
|
|
|
if (!data->source_uri)
|
|
return NErr_Empty;
|
|
|
|
*source_uri = NXURIRetain(data->source_uri);
|
|
return NErr_Success;
|
|
}
|
|
|
|
int NXDataGetSourceStat(nx_data_t data, nx_file_stat_t *source_stats)
|
|
{
|
|
if (!data)
|
|
return NErr_BadParameter;
|
|
|
|
if (!data->source_stats)
|
|
return NErr_Empty;
|
|
|
|
*source_stats = data->source_stats;
|
|
return NErr_Success;
|
|
}
|