#include "nx/nxdata.h" #include "foundation/atomics.h" #include "foundation/error.h" #include "nx/nxfile.h" #include /* 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; }