Index: src/OFFile.m ================================================================== --- src/OFFile.m +++ src/OFFile.m @@ -251,12 +251,12 @@ eos = YES; return ret; } -- (size_t)writeNBytes: (size_t)size - fromBuffer: (const char*)buf +- (size_t)writeNBytesWithoutCache: (size_t)size + fromBuffer: (const char*)buf { size_t ret; if (fd == -1 || eos || (ret = write(fd, buf, size)) < size) @throw [OFWriteFailedException newWithClass: isa Index: src/OFSocket.m ================================================================== --- src/OFSocket.m +++ src/OFSocket.m @@ -65,12 +65,12 @@ eos = YES; return ret; } -- (size_t)writeNBytes: (size_t)size - fromBuffer: (const char*)buf +- (size_t)writeNBytesWithoutCache: (size_t)size + fromBuffer: (const char*)buf { ssize_t ret; if (sock == INVALID_SOCKET) @throw [OFNotConnectedException newWithClass: isa]; Index: src/OFStream.h ================================================================== --- src/OFStream.h +++ src/OFStream.h @@ -17,12 +17,13 @@ /** * \brief A base class for different types of streams. */ @interface OFStream: OFObject { - char *cache; - size_t cache_len; + char *cache, *wcache; + size_t cache_len, wcache_len; + BOOL use_wcache; } /** * Returns a boolean whether the end of the stream has been reached. * @@ -168,20 +169,47 @@ * stream has been reached. */ - (OFString*)readTillDelimiter: (OFString*)delimiter withEncoding: (enum of_string_encoding)encoding; +/** + * Caches all writes until flushWriteCache is called. + */ +- cacheWrites; + +/** + * Writes everything in the write cache to the stream. + */ +- flushWriteCache; + /** * Writes from a buffer into the stream. + * + * IMPORTANT: Do *NOT* override this in subclasses! Override + * writeNBytesWithoutCache:fromBuffer: instead, as otherwise, you *WILL* break + * caching and thus get broken results! * * \param buf The buffer from which the data is written to the stream * \param size The size of the data that should be written * \return The number of bytes written */ - (size_t)writeNBytes: (size_t)size fromBuffer: (const char*)buf; +/** + * Directly writes from a buffer into the stream without caching the data first. + * + * IMPORTANT: Do *NOT* use this! Use writeNBytes:fromBuffer: instead, as this is + * *ONLY* for being overriden in subclasses! + * + * \param buf The buffer from which the data is written to the stream + * \param size The size of the data that should be written + * \return The number of bytes written + */ +- (size_t)writeNBytesWithoutCache: (size_t)size + fromBuffer: (const char*)buf; + /** * Writes an uint8_t into the stream. * * \param int8 An uint8_t */ Index: src/OFStream.m ================================================================== --- src/OFStream.m +++ src/OFStream.m @@ -35,10 +35,11 @@ if (isa == [OFStream class]) @throw [OFNotImplementedException newWithClass: isa selector: _cmd]; cache = NULL; + wcache = NULL; return self; } - (BOOL)atEndOfStream @@ -456,14 +457,50 @@ } /* Get rid of a warning, never reached anyway */ assert(0); } + +- cacheWrites +{ + use_wcache = YES; + + return self; +} + +- flushWriteCache +{ + [self writeNBytesWithoutCache: wcache_len + fromBuffer: wcache]; + + [self freeMemory: wcache]; + wcache = NULL; + wcache_len = 0; + use_wcache = NO; + + return self; +} - (size_t)writeNBytes: (size_t)size fromBuffer: (const char*)buf { + if (!use_wcache) + return [self writeNBytesWithoutCache: size + fromBuffer: buf]; + else { + wcache = [self resizeMemory: wcache + toSize: wcache_len + size]; + memcpy(wcache + wcache_len, buf, size); + wcache_len += size; + + return size; + } +} + +- (size_t)writeNBytesWithoutCache: (size_t)size + fromBuffer: (const char*)buf +{ @throw [OFNotImplementedException newWithClass: isa selector: _cmd]; } - (void)writeInt8: (uint8_t)int8 @@ -508,27 +545,14 @@ fromBuffer: [str cString]]; } - (size_t)writeLine: (OFString*)str { - size_t len = [str cStringLength]; - char *tmp; - - tmp = [self allocMemoryWithSize: len + 2]; - memcpy(tmp, [str cString], len); - tmp[len] = '\n'; - tmp[len + 1] = '\0'; - - @try { - return [self writeNBytes: len + 1 - fromBuffer: tmp]; - } @finally { - [self freeMemory: tmp]; - } - - /* Get rid of a warning, never reached anyway */ - assert(0); + size_t ret = [self writeString: str]; + [self writeInt8: '\n']; + + return ret + 1; } - (size_t)writeFormat: (OFString*)fmt, ... { va_list args;