123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525 |
- #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();
- }
|