Index: src/Makefile ================================================================== --- src/Makefile +++ src/Makefile @@ -14,23 +14,23 @@ OFIterator.m \ OFList.m \ OFNumber.m \ OFObject.m \ ${OFPLUGIN_M} \ + OFStream.m \ OFString.m \ OFTCPSocket.m \ OFThread.m \ OFXMLFactory.m \ ${ASPRINTF_C} INCLUDESTMP = ${SRCS:.c=.h} INCLUDES = ${INCLUDESTMP:.m=.h} \ - OFMacros.h \ - OFStream.h + OFMacros.h include ../buildsys.mk CPPFLAGS += -I.. CFLAGS += ${LIB_CFLAGS} OBJCFLAGS += ${LIB_CFLAGS} LD = ${OBJC} LDFLAGS += ${LIB_LDFLAGS} Index: src/OFFile.h ================================================================== --- src/OFFile.h +++ src/OFFile.h @@ -16,17 +16,16 @@ #else typedef int uid_t; typedef int gid_t; #endif -#import "OFObject.h" #import "OFStream.h" /** * The OFFile class provides functions to read, write and manipulate files. */ -@interface OFFile: OFObject +@interface OFFile: OFStream { FILE *fp; } /** Index: src/OFStream.h ================================================================== --- src/OFStream.h +++ src/OFStream.h @@ -7,14 +7,21 @@ * This file is part of libobjfw. 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 "OFObject.h" + /** - * The OFStream protocol provides functions to read from and write to streams. + * The OFStream class provides a base class for different types of streams. */ -@protocol OFStream +@interface OFStream: OFObject +{ + char *cache; + size_t cache_len; +} + /** * Reads from the stream into a buffer. * * \param buf The buffer into which the data is read * \param size The size of the data that should be read. @@ -22,10 +29,20 @@ * \return The number of bytes read */ - (size_t)readNBytes: (size_t)size intoBuffer: (char*)buf; +/** + * Read until a newline or \0 occurs. + * + * If you want to use readNBytes afterwards again, you have to clear the cache + * before and optionally get the cache before clearing it! + * + * \return The line that was read. Use freeMem: to free it! + */ +- (char*)readLine; + /** * Writes from a buffer into the stream. * * \param buf The buffer from which the data is written to the stream * \param size The size of the data that should be written @@ -40,10 +57,24 @@ * \param str The C string from which the data is written to the stream * \return The number of bytes written */ - (size_t)writeCString: (const char*)str; +/** + * Sets a specified pointer to the cache and returns the length of the cache. + * + * \param ptr A pointer to a pointer. It will be set to the cache. + * If it is NULL, only the number of bytes in the cache is returned. + * \return The number of bytes in the cache. + */ +- (size_t)getCache: (char**)ptr; + +/** + * Clears the cache. + */ +- clearCache; + /** * Closes the stream. */ - close; @end ADDED src/OFStream.m Index: src/OFStream.m ================================================================== --- src/OFStream.m +++ src/OFStream.m @@ -0,0 +1,177 @@ +/* + * Copyright (c) 2008 - 2009 + * Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of libobjfw. 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 + +#include +#include + +#import "OFStream.h" +#import "OFExceptions.h" +#import "OFMacros.h" + +extern int getpagesize(void); + +@implementation OFStream +- init +{ + self = [super init]; + + cache = NULL; + cache_len = 0; + + return self; +} + +- (size_t)readNBytes: (size_t)size + intoBuffer: (char*)buf +{ + @throw [OFNotImplementedException newWithClass: isa + andSelector: _cmd]; +} + +- (char*)readLine +{ + size_t i, len; + char *ret, *tmp, *tmp2; + + /* Look if there's a line or \0 in our cache */ + if (cache != NULL) { + for (i = 0; i < cache_len; i++) { + if (OF_UNLIKELY(cache[i] == '\n' || + cache[i] == '\0')) { + ret = [self allocWithSize: i + 1]; + memcpy(ret, cache, i); + ret[i] = '\0'; + + @try { + tmp = [self allocWithSize: cache_len - + i - 1]; + } @catch (OFException *e) { + [self freeMem: ret]; + @throw e; + } + memcpy(tmp, cache + i + 1, cache_len - i - 1); + + [self freeMem: cache]; + cache = tmp; + cache_len = cache_len - i - 1; + + return ret; + } + } + } + + /* Read until we get a newline or \0 */ + tmp = [self allocWithSize: getpagesize()]; + + for (;;) { + @try { + len = [self readNBytes: getpagesize() - 1 + intoBuffer: tmp]; + } @catch (OFException *e) { + [self freeMem: tmp]; + @throw e; + } + + /* Look if there's a newline or \0 */ + for (i = 0; i < len; i++) { + if (OF_UNLIKELY(tmp[i] == '\n' || tmp[i] == '\0')) { + @try { + ret = [self + allocWithSize: cache_len + i + 1]; + } @catch (OFException *e) { + [self freeMem: tmp]; + @throw e; + } + if (cache != NULL) + memcpy(ret, cache, cache_len); + memcpy(ret + cache_len, tmp, i); + ret[i] = '\0'; + + if (i < len) { + @try { + tmp2 = [self + allocWithSize: len - i - 1]; + } @catch (OFException *e) { + [self freeMem: ret]; + [self freeMem: tmp]; + @throw e; + } + memcpy(tmp2, tmp + i + 1, len - i - 1); + + if (cache != NULL) + [self freeMem: cache]; + cache = tmp2; + cache_len = len - i - 1; + } else { + if (cache != NULL) + [self freeMem: cache]; + cache = NULL; + cache_len = 0; + } + + [self freeMem: tmp]; + return ret; + } + } + + /* There was no newline or \0 */ + @try { + cache = [self resizeMem: cache + toSize: cache_len + len]; + } @catch (OFException *e) { + [self freeMem: tmp]; + @throw e; + } + memcpy(cache + cache_len, tmp, len); + cache_len += len; + } +} + +- (size_t)writeNBytes: (size_t)size + fromBuffer: (const char*)buf +{ + @throw [OFNotImplementedException newWithClass: isa + andSelector: _cmd]; +} + +- (size_t)writeCString: (const char*)str +{ + @throw [OFNotImplementedException newWithClass: isa + andSelector: _cmd]; +} + +- (size_t)getCache: (char**)ptr +{ + if (ptr != NULL) + *ptr = cache; + + return cache_len; +} + +- clearCache +{ + if (cache != NULL) + [self freeMem: cache]; + + cache = NULL; + cache_len = 0; + + return self; +} + +- close +{ + @throw [OFNotImplementedException newWithClass: isa + andSelector: _cmd]; +} +@end Index: src/OFTCPSocket.h ================================================================== --- src/OFTCPSocket.h +++ src/OFTCPSocket.h @@ -18,11 +18,10 @@ #include #include #include #endif -#import "OFObject.h" #import "OFStream.h" /* * Headers for Win32 * @@ -35,21 +34,19 @@ #endif /** * The OFTCPSocket class provides functions to create and use sockets. */ -@interface OFTCPSocket: OFObject +@interface OFTCPSocket: OFStream { #ifndef _WIN32 int sock; #else SOCKET sock; #endif struct sockaddr *saddr; socklen_t saddr_len; - char *cache; - size_t cache_len; } /** * \return A new autoreleased OFTCPSocket */ @@ -99,34 +96,10 @@ * \return An OFTCPSocket for the accepted connection, which is NOT * autoreleased! */ - (OFTCPSocket*)accept; -/** - * Read until a newline or \0 occurs. - * - * If you want to use readNBytes afterwards again, you have to clear the cache - * before and optionally get the cache before clearing it! - * - * \return The line that was read. Use freeMem: to free it! - */ -- (char*)readLine; - -/** - * Sets a specified pointer to the cache and returns the length of the cache. - * - * \param ptr A pointer to a pointer. It will be set to the cache. - * If it is NULL, only the number of bytes in the cache is returned. - * \return The number of bytes in the cache. - */ -- (size_t)getCache: (char**)ptr; - -/** - * Clears the cache. - */ -- clearCache; - /** * Enables/disables non-blocking I/O. */ - setBlocking: (BOOL)enable; Index: src/OFTCPSocket.m ================================================================== --- src/OFTCPSocket.m +++ src/OFTCPSocket.m @@ -17,18 +17,15 @@ #include #include #import "OFTCPSocket.h" #import "OFExceptions.h" -#import "OFMacros.h" #ifndef INVALID_SOCKET #define INVALID_SOCKET -1 #endif -extern int getpagesize(void); - @implementation OFTCPSocket + tcpSocket { return [[[OFTCPSocket alloc] init] autorelease]; } @@ -50,12 +47,10 @@ self = [super init]; sock = INVALID_SOCKET; saddr = NULL; saddr_len = 0; - cache = NULL; - cache_len = 0; return self; } - free @@ -229,128 +224,10 @@ /* This is safe, as we already checked < 1 */ return ret; } -- (char*)readLine -{ - size_t i, len; - char *ret, *tmp, *tmp2; - - /* Look if there's a line or \0 in our cache */ - if (cache != NULL) { - for (i = 0; i < cache_len; i++) { - if (OF_UNLIKELY(cache[i] == '\n' || - cache[i] == '\0')) { - ret = [self allocWithSize: i + 1]; - memcpy(ret, cache, i); - ret[i] = '\0'; - - @try { - tmp = [self allocWithSize: cache_len - - i - 1]; - } @catch (OFException *e) { - [self freeMem: ret]; - @throw e; - } - memcpy(tmp, cache + i + 1, cache_len - i - 1); - - [self freeMem: cache]; - cache = tmp; - cache_len = cache_len - i - 1; - - return ret; - } - } - } - - /* Read until we get a newline or \0 */ - tmp = [self allocWithSize: getpagesize()]; - - for (;;) { - @try { - len = [self readNBytes: getpagesize() - 1 - intoBuffer: tmp]; - } @catch (OFException *e) { - [self freeMem: tmp]; - @throw e; - } - - /* Look if there's a newline or \0 */ - for (i = 0; i < len; i++) { - if (OF_UNLIKELY(tmp[i] == '\n' || tmp[i] == '\0')) { - @try { - ret = [self - allocWithSize: cache_len + i + 1]; - } @catch (OFException *e) { - [self freeMem: tmp]; - @throw e; - } - if (cache != NULL) - memcpy(ret, cache, cache_len); - memcpy(ret + cache_len, tmp, i); - ret[i] = '\0'; - - if (i < len) { - @try { - tmp2 = [self - allocWithSize: len - i - 1]; - } @catch (OFException *e) { - [self freeMem: ret]; - [self freeMem: tmp]; - @throw e; - } - memcpy(tmp2, tmp + i + 1, len - i - 1); - - if (cache != NULL) - [self freeMem: cache]; - cache = tmp2; - cache_len = len - i - 1; - } else { - if (cache != NULL) - [self freeMem: cache]; - cache = NULL; - cache_len = 0; - } - - [self freeMem: tmp]; - return ret; - } - } - - /* There was no newline or \0 */ - @try { - cache = [self resizeMem: cache - toSize: cache_len + len]; - } @catch (OFException *e) { - [self freeMem: tmp]; - @throw e; - } - memcpy(cache + cache_len, tmp, len); - cache_len += len; - } -} - -- (size_t)getCache: (char**)ptr -{ - if (ptr != NULL) - *ptr = cache; - - return cache_len; -} - -- clearCache -{ - if (cache != NULL) - [self freeMem: cache]; - - cache = NULL; - cache_len = 0; - - return self; -} - - (size_t)writeNBytes: (size_t)size fromBuffer: (const char*)buf { ssize_t ret;