@@ -35,10 +35,11 @@ #import "OFInitializationFailedException.h" #import "OFInvalidArgumentException.h" #import "OFNotOpenException.h" #import "OFOpenItemFailedException.h" +#import "OFOutOfMemoryException.h" #import "OFOutOfRangeException.h" #import "OFReadFailedException.h" #import "OFSeekFailedException.h" #import "OFWriteFailedException.h" @@ -71,35 +72,37 @@ #endif #ifndef OF_MORPHOS # define closeHandle(h) close(h) #else -static OFDataArray *openHandles = nil; +struct of_file_handle { + of_file_handle_t previous, next; + BPTR handle; + bool append; +} *firstHandle = NULL; static void closeHandle(of_file_handle_t handle) { - if (handle.index != SIZE_MAX) { - BPTR *handles = [openHandles items]; - size_t count = [openHandles count]; - - assert(handles[handle.index] == handle.handle); - - handles[handle.index] = handles[count - 1]; - [openHandles removeItemAtIndex: count - 1]; - } - - Close(handle.handle); + Close(handle->handle); + + if (handle->previous != NULL) + handle->previous->next = handle->next; + if (handle->next != NULL) + handle->next->previous = handle->previous; + + if (firstHandle == handle) + firstHandle = handle->next; + + free(handle); } OF_DESTRUCTOR() { - BPTR *handles = [openHandles items]; - size_t count = [openHandles count]; - - for (size_t i = 0; i < count; i++) - Close(handles[i]); + for (of_file_handle_t iter = firstHandle; iter != NULL; + iter = iter->next) + Close(iter->handle); } #endif #ifndef OF_MORPHOS static int @@ -191,14 +194,10 @@ + (void)initialize { if (self != [OFFile class]) return; -#ifdef OF_MORPHOS - openHandles = [[OFDataArray alloc] initWithItemSize: sizeof(BPTR)]; -#endif - #ifdef OF_WII if (!fatInitDefault()) @throw [OFInitializationFailedException exceptionWithClass: self]; #endif @@ -255,57 +254,70 @@ @throw [OFOpenItemFailedException exceptionWithPath: path mode: mode errNo: errno]; #else - handle.index = SIZE_MAX; - - if ((flags = parseMode([mode UTF8String], - &handle.append)) == -1) - @throw [OFInvalidArgumentException exception]; - - if ((handle.handle = Open([path cStringWithEncoding: - [OFLocalization encoding]], flags)) == 0) { - int errNo; - - switch (IoErr()) { - case ERROR_OBJECT_IN_USE: - case ERROR_DISK_NOT_VALIDATED: - errNo = EBUSY; - break; - case ERROR_OBJECT_NOT_FOUND: - errNo = ENOENT; - break; - case ERROR_DISK_WRITE_PROTECTED: - errNo = EROFS; - break; - case ERROR_WRITE_PROTECTED: - case ERROR_READ_PROTECTED: - errNo = EACCES; - break; - default: - errNo = 0; - break; - } - - @throw [OFOpenItemFailedException - exceptionWithPath: path - mode: mode - errNo: errNo]; - } - - [openHandles addItem: &handle.handle]; - handle.index = [openHandles count] - 1; - - if (handle.append) { - if (Seek64(handle.handle, 0, OFFSET_END) == -1) { - closeHandle(handle); - @throw [OFOpenItemFailedException - exceptionWithPath: path - mode: mode - errNo: EIO]; - } + if ((handle = malloc(sizeof(*handle))) == NULL) + @throw [OFOutOfMemoryException + exceptionWithRequestedSize: sizeof(*handle)]; + + @try { + if ((flags = parseMode([mode UTF8String], + &handle->append)) == -1) + @throw [OFInvalidArgumentException exception]; + + if ((handle->handle = Open([path cStringWithEncoding: + [OFLocalization encoding]], flags)) == 0) { + int errNo; + + switch (IoErr()) { + case ERROR_OBJECT_IN_USE: + case ERROR_DISK_NOT_VALIDATED: + errNo = EBUSY; + break; + case ERROR_OBJECT_NOT_FOUND: + errNo = ENOENT; + break; + case ERROR_DISK_WRITE_PROTECTED: + errNo = EROFS; + break; + case ERROR_WRITE_PROTECTED: + case ERROR_READ_PROTECTED: + errNo = EACCES; + break; + default: + errNo = 0; + break; + } + + @throw [OFOpenItemFailedException + exceptionWithPath: path + mode: mode + errNo: errNo]; + } + + if (handle->append) { + if (Seek64(handle->handle, 0, + OFFSET_END) == -1) { + Close(handle->handle); + @throw [OFOpenItemFailedException + exceptionWithPath: path + mode: mode + errNo: EIO]; + } + } + + handle->previous = NULL; + handle->next = firstHandle; + + if (firstHandle != NULL) + firstHandle->previous = handle; + + firstHandle = handle; + } @catch (id e) { + free(handle); + @throw e; } #endif objc_autoreleasePoolPop(pool); } @catch (id e) { @@ -332,11 +344,11 @@ return self; } - (bool)lowlevelIsAtEndOfStream { - if (!OF_FILE_HANDLE_IS_VALID(_handle)) + if (_handle == OF_INVALID_FILE_HANDLE) @throw [OFNotOpenException exceptionWithObject: self]; return _atEndOfStream; } @@ -343,11 +355,11 @@ - (size_t)lowlevelReadIntoBuffer: (void *)buffer length: (size_t)length { ssize_t ret; - if (!OF_FILE_HANDLE_IS_VALID(_handle)) + if (_handle == OF_INVALID_FILE_HANDLE) @throw [OFNotOpenException exceptionWithObject: self]; #if defined(OF_WINDOWS) if (length > UINT_MAX) @throw [OFOutOfRangeException exception]; @@ -358,11 +370,11 @@ errNo: errno]; #elif defined(OF_MORPHOS) if (length > LONG_MAX) @throw [OFOutOfRangeException exception]; - if ((ret = Read(_handle.handle, buffer, length)) < 0) + if ((ret = Read(_handle->handle, buffer, length)) < 0) @throw [OFReadFailedException exceptionWithObject: self requestedLength: length errNo: EIO]; #else if ((ret = read(_handle, buffer, length)) < 0) @@ -378,11 +390,11 @@ } - (void)lowlevelWriteBuffer: (const void *)buffer length: (size_t)length { - if (!OF_FILE_HANDLE_IS_VALID(_handle)) + if (_handle == OF_INVALID_FILE_HANDLE) @throw [OFNotOpenException exceptionWithObject: self]; #if defined(OF_WINDOWS) if (length > INT_MAX) @throw [OFOutOfRangeException exception]; @@ -393,19 +405,19 @@ errNo: errno]; #elif defined(OF_MORPHOS) if (length > LONG_MAX) @throw [OFOutOfRangeException exception]; - if (_handle.append) { - if (Seek64(_handle.handle, 0, OFFSET_END) == -1) + if (_handle->append) { + if (Seek64(_handle->handle, 0, OFFSET_END) == -1) @throw [OFWriteFailedException exceptionWithObject: self requestedLength: length errNo: EIO]; } - if (Write(_handle.handle, (void *)buffer, length) != (LONG)length) + if (Write(_handle->handle, (void *)buffer, length) != (LONG)length) @throw [OFWriteFailedException exceptionWithObject: self requestedLength: length errNo: EIO]; #else if (length > SSIZE_MAX) @@ -421,11 +433,11 @@ - (of_offset_t)lowlevelSeekToOffset: (of_offset_t)offset whence: (int)whence { of_offset_t ret; - if (!OF_FILE_HANDLE_IS_VALID(_handle)) + if (_handle == OF_INVALID_FILE_HANDLE) @throw [OFNotOpenException exceptionWithObject: self]; #ifndef OF_MORPHOS # if defined(OF_WINDOWS) ret = _lseeki64(_handle, offset, whence); @@ -441,17 +453,17 @@ whence: whence errNo: errno]; #else switch (whence) { case SEEK_SET: - ret = Seek64(_handle.handle, offset, OFFSET_BEGINNING); + ret = Seek64(_handle->handle, offset, OFFSET_BEGINNING); break; case SEEK_CUR: - ret = Seek64(_handle.handle, offset, OFFSET_CURRENT); + ret = Seek64(_handle->handle, offset, OFFSET_CURRENT); break; case SEEK_END: - ret = Seek64(_handle.handle, offset, OFFSET_END); + ret = Seek64(_handle->handle, offset, OFFSET_END); break; default: ret = -1; break; } @@ -480,11 +492,11 @@ } #endif - (void)close { - if (OF_FILE_HANDLE_IS_VALID(_handle)) + if (_handle != OF_INVALID_FILE_HANDLE) closeHandle(_handle); _handle = OF_INVALID_FILE_HANDLE; [super close];