diff options
author | Jef <jef@targetspot.com> | 2024-09-24 08:54:57 -0400 |
---|---|---|
committer | Jef <jef@targetspot.com> | 2024-09-24 08:54:57 -0400 |
commit | 20d28e80a5c861a9d5f449ea911ab75b4f37ad0d (patch) | |
tree | 12f17f78986871dd2cfb0a56e5e93b545c1ae0d0 /Src/replicant/nx/win/NXFileObject.cpp | |
parent | 537bcbc86291b32fc04ae4133ce4d7cac8ebe9a7 (diff) | |
download | winamp-20d28e80a5c861a9d5f449ea911ab75b4f37ad0d.tar.gz |
Initial community commit
Diffstat (limited to 'Src/replicant/nx/win/NXFileObject.cpp')
-rw-r--r-- | Src/replicant/nx/win/NXFileObject.cpp | 525 |
1 files changed, 525 insertions, 0 deletions
diff --git a/Src/replicant/nx/win/NXFileObject.cpp b/Src/replicant/nx/win/NXFileObject.cpp new file mode 100644 index 00000000..8f1255db --- /dev/null +++ b/Src/replicant/nx/win/NXFileObject.cpp @@ -0,0 +1,525 @@ +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#include <windows.h> +#include "NXFileObject.h" + +#include "nx/nxfile.h" +#include "nu/nodelist.h" +#include "foundation/atomics.h" +#include "nu/nodelist.h" +#include <errno.h> +#include <new> + +/* Windows implementation +note: for now, we're using FILE. We will eventually replace with better buffering + +TODO: deal with files opened in "append" mode */ + +NXFileObject::NXFileObject() +{ + nodelist_init(®ion_stack); + region.start = 0; + region.end = 0xFFFFFFFFFFFFFFFFULL; + position=0; + reference_count=1; + uri=0; + memset(&file_stats, 0, sizeof(file_stats)); +} + +NXFileObject::~NXFileObject() +{ + NXURIRelease(uri); + NXFileRegion *region = (NXFileRegion *)region_stack.head; + while (region) + { + NXFileRegion *next = (NXFileRegion *)region->Next; + free(region); + region = next; + } +} + +ns_error_t NXFileObject::Initialize(nx_uri_t _uri) +{ + uri = NXURIRetain(_uri); + return NErr_Success; +} + +size_t NXFileObject::Retain() +{ + return nx_atomic_inc(&reference_count); +} + +size_t NXFileObject::Release() +{ + if (!reference_count) + { + return reference_count; + } + size_t r = nx_atomic_dec_release(&reference_count); + if (!r) + { + delete(this); + } + return r; +} + +ns_error_t NXFileObject::LockRegion(uint64_t start, uint64_t end) +{ + // save the old region data + NXFileRegion *old_region = (NXFileRegion *)calloc(1, sizeof(NXFileRegion)); + if (!old_region) + { + return NErr_OutOfMemory; + } + old_region->start = region.start; + old_region->end = region.end; + nodelist_push_front(®ion_stack, old_region); + + // if we're already locked, Lock within our current region. + // The weird way the logic is done prevents overflow + if (start > region.end - region.start) + { + start = region.end; + } + else + { + start = region.start + start; + } + + if (end > region.end - region.start) + { + end = region.end; + } + else + { + end = region.start + end; + } + + region.start = start; + region.end = end; + return NErr_Success; +} + +ns_error_t NXFileObject::UnlockRegion() +{ + NXFileRegion *new_region = (NXFileRegion *)nodelist_pop_front(®ion_stack); + if (new_region) + { + region.start = new_region->start; + region.end = new_region->end; + free(new_region); + return NErr_Success; + } + else + { + return NErr_NoAction; + } +} + +ns_error_t NXFileObject::Stat(nx_file_stat_t out_stats) +{ + *out_stats = file_stats; + return NErr_Success; +} + +ns_error_t NXFileObject::Length(uint64_t *length) +{ + *length = region.end - region.start; + return NErr_Success; +} + +ns_error_t NXFileObject::EndOfFile() +{ + if (position >= region.end) + { + return NErr_True; + } + else + { + return NErr_False; + } +} +/* ----------------------------------------- */ + +class NXFileObject_FILE : public NXFileObject +{ +public: + NXFileObject_FILE(); + ~NXFileObject_FILE(); + ns_error_t Initialize(nx_uri_t uri, FILE *f, bool writable); + +private: + FILE *f; + bool writable; + + ns_error_t Read(void *buffer, size_t bytes_requested, size_t *bytes_read); + ns_error_t Write(const void *buffer, size_t bytes); + ns_error_t Seek(uint64_t position); + ns_error_t Tell(uint64_t *position); + ns_error_t PeekByte(uint8_t *byte); + ns_error_t Sync(); + ns_error_t Truncate(); +}; + +NXFileObject_FILE::NXFileObject_FILE() +{ + f = 0; + writable = false; +} + +NXFileObject_FILE::~NXFileObject_FILE() +{ + if (f) + { + fclose(f); + } +} + +ns_error_t NXFileObject_FILE::Initialize(nx_uri_t uri, FILE *_f, bool _writable) +{ + writable = _writable; + + ns_error_t ret = NXFileObject::Initialize(uri); + if (ret != NErr_Success) + { + return ret; + } + + ret = NXFile_statFILE(_f, &file_stats); + if (ret != NErr_Success) + { + return ret; + } + + region.end = file_stats.file_size; + + f = _f; + return NErr_Success; +} + +ns_error_t NXFileObject_FILE::Read(void *buffer, size_t bytes_requested, size_t *bytes_read) +{ + // if it's an "empty" read, we need to determine whether or not we're at the end of the file + if (bytes_requested == 0) + { + if (region.end == position || feof(f)) + { + return NErr_EndOfFile; + } + else + { + return NErr_Success; + } + } + + // don't read into any data after the locked region + if ((uint64_t)bytes_requested > region.end - position) + { + bytes_requested = (size_t)(region.end - position); + } + + if (bytes_requested == 0) + { + return NErr_EndOfFile; + } + + if (buffer == 0) + { + uint64_t old_position=position; + Seek(position+bytes_requested); + if (bytes_read) + { + *bytes_read = (size_t)(position - old_position); + } + return NErr_Success; + } + else + { + size_t results = fread(buffer, 1, bytes_requested, f); + if (results == 0) + { + if (feof(f)) + { + return NErr_EndOfFile; + } + else + { + return NErr_Error; + } + } + if (bytes_read) + { + *bytes_read = results; + } + position+=results; + return NErr_Success; + } +} + +ns_error_t NXFileObject_FILE::Write(const void *buffer, size_t bytes) +{ + // TODO: review this in relation to locked regions + size_t results = fwrite(buffer, 1, bytes, f); + if (results == 0) + { + return NErr_Error; + } + + position += results; + if (region.end < position) + { + region.end = position; + } + return NErr_Success; +} + +ns_error_t NXFileObject_FILE::PeekByte(uint8_t *byte) +{ + if (position == region.end) + { + return NErr_EndOfFile; + } + + int read_byte = fgetc(f); + if (read_byte != EOF) + { + ungetc(read_byte, f); + } + else + { + return NErr_EndOfFile; + } + + *byte = (uint8_t)read_byte; + return NErr_Success; +} + +ns_error_t NXFileObject_FILE::Seek(uint64_t new_position) +{ + if (!writable) + { + // doing it this way will prevent integer overflow + if (new_position > (region.end - region.start)) + { + new_position = region.end - region.start; + } + } + + if (_fseeki64(f, region.start+new_position, SEEK_SET) == 0) + { + position = region.start+new_position; + return NErr_Success; + } + else + { + return NErr_Error; + } +} + +ns_error_t NXFileObject_FILE::Tell(uint64_t *out_position) +{ + *out_position = position - region.start; + return NErr_Success; +} + +ns_error_t NXFileObject_FILE::Sync() +{ + fflush(f); + return NErr_Success; +} + +ns_error_t NXFileObject_FILE::Truncate() +{ + int fd = _fileno(f); + _chsize_s(fd, position); + return NErr_Success; +} + +/* ----------------------------------------- */ +ns_error_t NXFileOpenFile(nx_file_t *out_file, nx_uri_t filename, nx_file_FILE_flags_t flags) +{ + FILE *f = NXFile_fopen(filename, flags); + if (!f) + { + if (errno == ENOENT) + { + return NErr_FileNotFound; + } + else + { + return NErr_Error; + } + } + + NXFileObject_FILE *file_object = new (std::nothrow) NXFileObject_FILE; + if (!file_object) + { + fclose(f); + return NErr_OutOfMemory; + } + + ns_error_t ret = file_object->Initialize(filename, f, !!(flags & nx_file_FILE_writable_mask)); + if (ret != NErr_Success) + { + fclose(f); + delete file_object; + return ret; + } + + *out_file = (nx_file_t)file_object; + return NErr_Success; +} + +nx_file_t NXFileRetain(nx_file_t _f) +{ + if (!_f) + { + return 0; + } + + NXFileObject *f = (NXFileObject *)_f; + f->Retain(); + return _f; +} + +void NXFileRelease(nx_file_t _f) +{ + if (_f) + { + NXFileObject *f = (NXFileObject *)_f; + f->Release(); + } +} + +ns_error_t NXFileRead(nx_file_t _f, void *buffer, size_t bytes_requested, size_t *bytes_read) +{ + if (!_f) + { + return NErr_BadParameter; + } + + NXFileObject *f = (NXFileObject *)_f; + return f->Read(buffer, bytes_requested, bytes_read); +} + +ns_error_t NXFileSeek(nx_file_t _f, uint64_t position) +{ + if (!_f) + { + return NErr_BadParameter; + } + + NXFileObject *f = (NXFileObject *)_f; + return f->Seek(position); +} + +ns_error_t NXFileTell(nx_file_t _f, uint64_t *position) +{ + if (!_f) + { + return NErr_BadParameter; + } + + NXFileObject *f = (NXFileObject *)_f; + return f->Tell(position); +} + +ns_error_t NXFileLockRegion(nx_file_t _f, uint64_t start_position, uint64_t end_position) +{ + if (!_f) + { + return NErr_BadParameter; + } + + NXFileObject *f = (NXFileObject *)_f; + return f->LockRegion(start_position, end_position); +} + +ns_error_t NXFileUnlockRegion(nx_file_t _f) +{ + if (!_f) + { + return NErr_BadParameter; + } + + NXFileObject *f = (NXFileObject *)_f; + return f->UnlockRegion(); +} + +ns_error_t NXFileStat(nx_file_t _f, nx_file_stat_t file_stats) +{ + if (!_f) + { + return NErr_BadParameter; + } + + NXFileObject *f = (NXFileObject *)_f; + return f->Stat(file_stats); +} + +ns_error_t NXFileLength(nx_file_t _f, uint64_t *length) +{ + if (!_f) + { + return NErr_BadParameter; + } + + NXFileObject *f = (NXFileObject *)_f; + return f->Length(length); +} + +ns_error_t NXFileEndOfFile(nx_file_t _f) +{ + if (!_f) + { + return NErr_BadParameter; + } + + NXFileObject *f = (NXFileObject *)_f; + return f->EndOfFile(); +} + +ns_error_t NXFilePeekByte(nx_file_t _f, uint8_t *byte) +{ + if (!_f) + { + return NErr_BadParameter; + } + + NXFileObject *f = (NXFileObject *)_f; + return f->PeekByte(byte); +} + +ns_error_t NXFileWrite(nx_file_t _f, const void *buffer, size_t bytes) +{ + if (!_f) + { + return NErr_BadParameter; + } + + NXFileObject *f = (NXFileObject *)_f; + return f->Write(buffer, bytes); +} + +ns_error_t NXFileSync(nx_file_t _f) +{ + if (!_f) + { + return NErr_BadParameter; + } + + NXFileObject *f = (NXFileObject *)_f; + return f->Sync(); +} + +ns_error_t NXFileTruncate(nx_file_t _f) +{ + if (!_f) + { + return NErr_BadParameter; + } + + NXFileObject *f = (NXFileObject *)_f; + return f->Truncate(); +}
\ No newline at end of file |