Artifact d552430548af5ead94380d7ad0bb74955bf8c83aaa337ff51d07c664926f9d06:
- File
src/OFStream.m
— part of check-in
[b91a8283fe]
at
2010-03-05 11:52:18
on branch 0.2
— Merge a few changesets from the default branch into the 0.2 branch.
Changesets:
* b95fcaa6d694
* 804c68d222b4
* da8cd738da3d
* 1109d5ce3419
* d03f5c1ca95d
* 2a7017722165
* 4fccdc79eeb7
* d228149fbc04
* 8782d412a4a6 (user: js, size: 4996) [annotate] [blame] [check-ins using]
/* * Copyright (c) 2008 - 2010 * Jonathan Schleifer <js@webkeks.org> * * 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 "config.h" #include <string.h> #include <unistd.h> #include <assert.h> #import "OFStream.h" #import "OFString.h" #import "OFExceptions.h" #import "OFMacros.h" #ifdef _WIN32 #include <windows.h> #endif static int pagesize = 0; @implementation OFStream - init { self = [super init]; if (isa == [OFStream class]) @throw [OFNotImplementedException newWithClass: isa selector: _cmd]; cache = NULL; #ifndef _WIN32 if (pagesize == 0) if ((pagesize = sysconf(_SC_PAGESIZE)) == -1) pagesize = 4096; #else if (pagesize == 0) { SYSTEM_INFO si; GetSystemInfo(&si); pagesize = si.dwPageSize - 1; } #endif return self; } - (BOOL)atEndOfStream { if (cache != NULL) return NO; return [self atEndOfStreamWithoutCache]; } - (BOOL)atEndOfStreamWithoutCache { @throw [OFNotImplementedException newWithClass: isa selector: _cmd]; } - (size_t)readNBytes: (size_t)size intoBuffer: (char*)buf { if (cache == NULL) return [self readNBytesWithoutCache: size intoBuffer: buf]; if (size >= cache_len) { size_t ret = cache_len; memcpy(buf, cache, cache_len); [self freeMemory: cache]; cache = NULL; cache_len = 0; return ret; } else { char *tmp = [self allocMemoryWithSize: cache_len - size]; memcpy(tmp, cache + size, cache_len - size); memcpy(buf, cache, size); [self freeMemory: cache]; cache = tmp; cache_len -= size; return size; } } - (size_t)readNBytesWithoutCache: (size_t)size intoBuffer: (char*)buf { @throw [OFNotImplementedException newWithClass: isa selector: _cmd]; } - (OFString*)readLine { return [self readLineWithEncoding: OF_STRING_ENCODING_UTF_8]; } - (OFString*)readLineWithEncoding: (enum of_string_encoding)encoding { size_t i, len, ret_len; char *ret_c, *tmp, *tmp2; OFString *ret; /* 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_len = i; if (i > 0 && cache[i - 1] == '\r') ret_len--; ret = [OFString stringWithCString: cache encoding: encoding length: ret_len]; tmp = [self allocMemoryWithSize: cache_len - i - 1]; memcpy(tmp, cache + i + 1, cache_len - i - 1); [self freeMemory: cache]; cache = tmp; cache_len -= i + 1; return ret; } } } /* Read until we get a newline or \0 */ tmp = [self allocMemoryWithSize: pagesize]; @try { for (;;) { if ([self atEndOfStreamWithoutCache]) { if (cache == NULL) return nil; ret_len = cache_len; if (ret_len > 0 && cache[ret_len - 1] == '\r') ret_len--; ret = [OFString stringWithCString: cache encoding: encoding length: ret_len]; [self freeMemory: cache]; cache = NULL; cache_len = 0; return ret; } len = [self readNBytesWithoutCache: pagesize intoBuffer: tmp]; /* Look if there's a newline or \0 */ for (i = 0; i < len; i++) { if (OF_UNLIKELY(tmp[i] == '\n' || tmp[i] == '\0')) { ret_len = cache_len + i; ret_c = [self allocMemoryWithSize: ret_len]; if (cache != NULL) memcpy(ret_c, cache, cache_len); memcpy(ret_c + cache_len, tmp, i); if (ret_len > 0 && ret_c[ret_len - 1] == '\r') ret_len--; @try { ret = [OFString stringWithCString: ret_c encoding: encoding length: ret_len]; } @finally { [self freeMemory: ret_c]; } if (i < len) { tmp2 = [self allocMemoryWithSize: len - i - 1]; memcpy(tmp2, tmp + i + 1, len - i - 1); [self freeMemory: cache]; cache = tmp2; cache_len = len - i - 1; } else { [self freeMemory: cache]; cache = NULL; cache_len = 0; } return ret; } } /* There was no newline or \0 */ cache = [self resizeMemory: cache toSize: cache_len + len]; /* * It's possible that cache_len + len is 0 and thus * cache was set to NULL by resizeMemory:toSize:. */ if (cache != NULL) memcpy(cache + cache_len, tmp, len); cache_len += len; } } @finally { [self freeMemory: tmp]; } /* Get rid of a warning, never reached anyway */ assert(0); } - (size_t)writeNBytes: (size_t)size fromBuffer: (const char*)buf { @throw [OFNotImplementedException newWithClass: isa selector: _cmd]; } - (size_t)writeString: (OFString*)str { return [self writeNBytes: [str cStringLength] fromBuffer: [str cString]]; } - close { @throw [OFNotImplementedException newWithClass: isa selector: _cmd]; } @end