Index: ObjFW.xcodeproj/project.pbxproj ================================================================== --- ObjFW.xcodeproj/project.pbxproj +++ ObjFW.xcodeproj/project.pbxproj @@ -126,10 +126,12 @@ 4B67998C1099E7C50041064A /* unicode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = unicode.h; path = src/unicode.h; sourceTree = ""; }; 4B6AF96C10A8D3E40003FB0A /* asprintf.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = asprintf.m; path = src/asprintf.m; sourceTree = ""; }; 4B6AF96F10A8D40E0003FB0A /* iso_8859_15.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = iso_8859_15.m; path = src/iso_8859_15.m; sourceTree = ""; }; 4B6AF97210A8D42E0003FB0A /* windows_1252.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = windows_1252.m; path = src/windows_1252.m; sourceTree = ""; }; 4B6AF97310A8D4450003FB0A /* ObjFW.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ObjFW.h; path = src/ObjFW.h; sourceTree = ""; }; + 4B981CDE116F71DD00294DB7 /* OFSeekableStream.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OFSeekableStream.h; path = src/OFSeekableStream.h; sourceTree = SOURCE_ROOT; }; + 4B981CDF116F71DD00294DB7 /* OFSeekableStream.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OFSeekableStream.m; path = src/OFSeekableStream.m; sourceTree = SOURCE_ROOT; }; 4BBA36C411406AB700CBA3AC /* atomic.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = atomic.h; path = src/atomic.h; sourceTree = SOURCE_ROOT; }; 4BBA36C511406AB700CBA3AC /* macros.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = macros.h; path = src/macros.h; sourceTree = SOURCE_ROOT; }; 4BFBDD1610A0724800051AFB /* unicode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = unicode.m; path = src/unicode.m; sourceTree = ""; }; /* End PBXFileReference section */ @@ -169,10 +171,12 @@ 4B6799761099E7C50041064A /* OFNumber.m */, 4B6799771099E7C50041064A /* OFObject.h */, 4B6799781099E7C50041064A /* OFObject.m */, 4B6799791099E7C50041064A /* OFPlugin.h */, 4B67997A1099E7C50041064A /* OFPlugin.m */, + 4B981CDE116F71DD00294DB7 /* OFSeekableStream.h */, + 4B981CDF116F71DD00294DB7 /* OFSeekableStream.m */, 4B67997B1099E7C50041064A /* OFSocket.h */, 4B67997C1099E7C50041064A /* OFSocket.m */, 4B67997D1099E7C50041064A /* OFStream.h */, 4B67997E1099E7C50041064A /* OFStream.m */, 4B67997F1099E7C50041064A /* OFString.h */, Index: src/Makefile ================================================================== --- src/Makefile +++ src/Makefile @@ -19,10 +19,11 @@ OFMutableDictionary.m \ OFMutableString.m \ OFNumber.m \ OFObject.m \ ${OFPLUGIN_M} \ + OFSeekableStream.m \ OFSocket.m \ OFStream.m \ OFString.m \ OFTCPSocket.m \ ${OFTHREAD_M} \ Index: src/OFExceptions.h ================================================================== --- src/OFExceptions.h +++ src/OFExceptions.h @@ -286,11 +286,11 @@ */ - (OFString*)mode; @end /** - * \brief An exception indicating a read or write to a file failed. + * \brief An exception indicating a read or write to a stream failed. */ @interface OFReadOrWriteFailedException: OFException { size_t req_size; int err; @@ -324,21 +324,35 @@ */ - (size_t)requestedSize; @end /** - * \brief An exception indicating a read on a file failed. + * \brief An exception indicating a read on a stream failed. */ @interface OFReadFailedException: OFReadOrWriteFailedException {} @end /** - * \brief An exception indicating a write to a file failed. + * \brief An exception indicating a write to a stream failed. */ @interface OFWriteFailedException: OFReadOrWriteFailedException {} @end +/** + * \brief An exception indicating that seeking in a stream failed. + */ +@interface OFSeekFailedException: OFException +{ + int err; +} + +/** + * \return The errno from when the exception was created + */ +- (int)errNo; +@end + /** * \brief An exception indicating that changing the mode of a file failed. */ @interface OFChangeFileModeFailedException: OFException { Index: src/OFExceptions.m ================================================================== --- src/OFExceptions.m +++ src/OFExceptions.m @@ -484,10 +484,38 @@ [class_ className], ERRPARAM]; return string; } @end + +@implementation OFSeekFailedException +- initWithClass: (Class)class__ +{ + self = [super initWithClass: class__]; + + err = GET_ERR; + + return self; +} + +- (OFString*)string +{ + if (string != nil) + return string; + + string = [[OFString alloc] initWithFormat: + @"Seeking failed in class %s! " ERRFMT, [class_ className], + ERRPARAM]; + + return string; +} + +- (int)errNo +{ + return err; +} +@end @implementation OFChangeFileModeFailedException + newWithClass: (Class)class__ path: (OFString*)path_ mode: (mode_t)mode_ Index: src/OFFile.h ================================================================== --- src/OFFile.h +++ src/OFFile.h @@ -7,22 +7,20 @@ * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE included in * the packaging of this file. */ -#include - #include -#import "OFStream.h" +#import "OFSeekableStream.h" @class OFString; /** * \brief A class which provides functions to read, write and manipulate files. */ -@interface OFFile: OFStream +@interface OFFile: OFSeekableStream { int fd; BOOL closable; BOOL eos; } Index: src/OFFile.m ================================================================== --- src/OFFile.m +++ src/OFFile.m @@ -252,10 +252,38 @@ if (fd == -1 || eos || (ret = write(fd, buf, size)) < size) @throw [OFWriteFailedException newWithClass: isa size: size]; + return ret; +} + +- _seekToOffset: (off_t)offset +{ + if (lseek(fd, offset, SEEK_SET) == -1) + @throw [OFSeekFailedException newWithClass: isa]; + + return self; +} + +- (size_t)_seekForwardWithOffset: (off_t)offset +{ + off_t ret; + + if ((ret = lseek(fd, offset, SEEK_CUR)) == -1) + @throw [OFSeekFailedException newWithClass: isa]; + + return ret; +} + +- (size_t)_seekToOffsetRelativeToEnd: (off_t)offset +{ + off_t ret; + + if ((ret = lseek(fd, offset, SEEK_END)) == -1) + @throw [OFSeekFailedException newWithClass: isa]; + return ret; } - close { ADDED src/OFSeekableStream.h Index: src/OFSeekableStream.h ================================================================== --- src/OFSeekableStream.h +++ src/OFSeekableStream.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2008 - 2010 + * Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE included in + * the packaging of this file. + */ + +#include + +#import "OFStream.h" + +/** + * \brief A stream that supports seeking. + * + * IMPORTANT: If you want to subclass this, override _seekToOffset:, + * _seekForwardWithOffset: and _seekToOffsetRelativeToEnd:, but nothing else. + * Those are not defined in the headers, but do the actual work. + * OFSeekableStream uses those and makes them work together with the caching of + * OFStream. If you override these methods without the _ prefix, you *WILL* + * break caching, get broken results and seek to the wrong position! + */ +@interface OFSeekableStream: OFStream +/** + * Seeks to the specified absolute offset. + * + * \param offset The offset in bytes + */ +- seekToOffset: (off_t)offset; + +/** + * Seeks to the specified offset, relative to the current location. + * + * \param offset The offset relative to the current location + * \return The absolute offset + */ +- (off_t)seekForwardWithOffset: (off_t)offset; + +/** + * Seeks to the specified offset, relative to the end of the stream. + * + * \param offset The offset relative to the end of the stream + * \return The absolute offset + */ +- (off_t)seekToOffsetRelativeToEnd: (off_t)offset; +@end ADDED src/OFSeekableStream.m Index: src/OFSeekableStream.m ================================================================== --- src/OFSeekableStream.m +++ src/OFSeekableStream.m @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2008 - 2010 + * Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE included in + * the packaging of this file. + */ + +#import "OFSeekableStream.h" +#import "OFExceptions.h" + +@implementation OFSeekableStream +- _seekToOffset: (off_t)offset +{ + @throw [OFNotImplementedException newWithClass: isa + selector: _cmd]; +} + +- (off_t)_seekForwardWithOffset: (off_t)offset +{ + @throw [OFNotImplementedException newWithClass: isa + selector: _cmd]; +} + +- (off_t)_seekToOffsetRelativeToEnd: (off_t)offset +{ + @throw [OFNotImplementedException newWithClass: isa + selector: _cmd]; +} + +- seekToOffset: (off_t)offset +{ + [self _seekToOffset: offset]; + + [self freeMemory: cache]; + cache = NULL; + cache_len = 0; + + return self; +} + +- (off_t)seekForwardWithOffset: (off_t)offset +{ + off_t ret; + + ret = [self _seekForwardWithOffset: offset - cache_len]; + + [self freeMemory: cache]; + cache = NULL; + cache_len = 0; + + return ret; +} + +- (off_t)seekToOffsetRelativeToEnd: (off_t)offset +{ + off_t ret = [self _seekToOffsetRelativeToEnd: offset]; + + [self freeMemory: cache]; + cache = NULL; + cache_len = 0; + + return ret; +} +@end