ObjFW  Check-in [7bf4b144ad]

Overview
Comment:Make OFStream a class instead of a protocol and move readLine there.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: 7bf4b144adc035b648a05ec4657daf6cb209ec59ada74f7cf46d8c9b42941fe3
User & Date: js on 2009-05-03 17:19:53
Other Links: manifest | tags
Context
2009-05-03
21:33
Get rid of + new.
Additionally, make - accept return an autoreleased OFTCPSocket.
check-in: 5ca127891c user: js tags: trunk
17:19
Make OFStream a class instead of a protocol and move readLine there. check-in: 7bf4b144ad user: js tags: trunk
15:49
Remove multiply overflow check in OFArray - it's done by resizeMem. check-in: 4eb87f934f user: js tags: trunk
Changes

Modified src/Makefile from [369dbcb763] to [c065590079].

12
13
14
15
16
17
18

19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
       OFFile.m			\
       OFHashes.m		\
       OFIterator.m		\
       OFList.m			\
       OFNumber.m		\
       OFObject.m		\
       ${OFPLUGIN_M}		\

       OFString.m		\
       OFTCPSocket.m		\
       OFThread.m		\
       OFXMLFactory.m		\
       ${ASPRINTF_C}

INCLUDESTMP = ${SRCS:.c=.h}
INCLUDES = ${INCLUDESTMP:.m=.h}	\
	   OFMacros.h		\
	   OFStream.h

include ../buildsys.mk

CPPFLAGS += -I..
CFLAGS += ${LIB_CFLAGS}
OBJCFLAGS += ${LIB_CFLAGS}
LD = ${OBJC}
LDFLAGS += ${LIB_LDFLAGS}







>








|
<








12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

29
30
31
32
33
34
35
36
       OFFile.m			\
       OFHashes.m		\
       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


include ../buildsys.mk

CPPFLAGS += -I..
CFLAGS += ${LIB_CFLAGS}
OBJCFLAGS += ${LIB_CFLAGS}
LD = ${OBJC}
LDFLAGS += ${LIB_LDFLAGS}

Modified src/OFFile.h from [35d6e43251] to [8b3e4349b5].

14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#ifndef _WIN32
#include <sys/types.h>
#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 <OFStream>
{
	FILE *fp;
}

/**
 * \param path The path to the file to open as a C string
 * \param mode The mode in which the file should be opened as a C string







<





|







14
15
16
17
18
19
20

21
22
23
24
25
26
27
28
29
30
31
32
33
#ifndef _WIN32
#include <sys/types.h>
#else
typedef int uid_t;
typedef int gid_t;
#endif


#import "OFStream.h"

/**
 * The OFFile class provides functions to read, write and manipulate files.
 */
@interface OFFile: OFStream
{
	FILE *fp;
}

/**
 * \param path The path to the file to open as a C string
 * \param mode The mode in which the file should be opened as a C string

Modified src/OFStream.h from [7f1379bb1f] to [b001002c07].

1
2
3
4
5
6
7
8
9
10
11


12
13
14
15





16
17
18
19
20
21
22
23
24
25
26










27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44














45
46
47
48
49
/*
 * Copyright (c) 2008 - 2009
 *   Jonathan Schleifer <js@webkeks.org>
 *
 * 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.
 */



/**
 * The OFStream protocol provides functions to read from and write to streams.
 */
@protocol OFStream





/**
 * 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.
 *	  The buffer MUST be at least size big!
 * \return The number of bytes read
 */
- (size_t)readNBytes: (size_t)size
	  intoBuffer: (char*)buf;











/**
 * 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
 * \return The number of bytes written
 */
- (size_t)writeNBytes: (size_t)size
	   fromBuffer: (const char*)buf;

/**
 * Writes a C string into the stream, without the trailing zero.
 *
 * \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;















/**
 * Closes the stream.
 */
- close;
@end











>
>

|

|
>
>
>
>
>











>
>
>
>
>
>
>
>
>
>


















>
>
>
>
>
>
>
>
>
>
>
>
>
>





1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
/*
 * Copyright (c) 2008 - 2009
 *   Jonathan Schleifer <js@webkeks.org>
 *
 * 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 "OFObject.h"

/**
 * The OFStream class provides a base class for different types of streams.
 */
@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.
 *	  The buffer MUST be at least size big!
 * \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
 * \return The number of bytes written
 */
- (size_t)writeNBytes: (size_t)size
	   fromBuffer: (const char*)buf;

/**
 * Writes a C string into the stream, without the trailing zero.
 *
 * \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 version [4ee7f03849].



































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
/*
 * Copyright (c) 2008 - 2009
 *   Jonathan Schleifer <js@webkeks.org>
 *
 * 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 <config.h>

#include <string.h>
#include <unistd.h>

#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

Modified src/OFTCPSocket.h from [68a22b9b8b] to [91d2dde531].

16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
 */
#ifndef _WIN32
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#endif

#import "OFObject.h"
#import "OFStream.h"

/*
 * Headers for Win32
 *
 * These must be imported after objc/Object and thus OFObject!
 */
#ifdef _WIN32
#define _WIN32_WINNT 0x0501
#include <winsock2.h>
#include <ws2tcpip.h>
#endif

/**
 * The OFTCPSocket class provides functions to create and use sockets.
 */
@interface OFTCPSocket: OFObject <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
 */
+ tcpSocket;








<
















|








<
<







16
17
18
19
20
21
22

23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47


48
49
50
51
52
53
54
 */
#ifndef _WIN32
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#endif


#import "OFStream.h"

/*
 * Headers for Win32
 *
 * These must be imported after objc/Object and thus OFObject!
 */
#ifdef _WIN32
#define _WIN32_WINNT 0x0501
#include <winsock2.h>
#include <ws2tcpip.h>
#endif

/**
 * The OFTCPSocket class provides functions to create and use sockets.
 */
@interface OFTCPSocket: OFStream
{
#ifndef _WIN32
	int		sock;
#else
	SOCKET		sock;
#endif
	struct sockaddr	*saddr;
	socklen_t	saddr_len;


}

/**
 * \return A new autoreleased OFTCPSocket
 */
+ tcpSocket;

97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
/**
 * Accept an incoming connection.
 * \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;

/**
 * Enable or disable keep alives for the connection.







<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







94
95
96
97
98
99
100
























101
102
103
104
105
106
107
/**
 * Accept an incoming connection.
 * \return An OFTCPSocket for the accepted connection, which is NOT
 *	   autoreleased!
 */
- (OFTCPSocket*)accept;

























/**
 * Enables/disables non-blocking I/O.
 */
- setBlocking: (BOOL)enable;

/**
 * Enable or disable keep alives for the connection.

Modified src/OFTCPSocket.m from [0f96f0fac9] to [645f0b0d2c].

15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>

#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];
}

#ifdef _WIN32







<





<
<







15
16
17
18
19
20
21

22
23
24
25
26


27
28
29
30
31
32
33
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>

#import "OFTCPSocket.h"
#import "OFExceptions.h"


#ifndef INVALID_SOCKET
#define INVALID_SOCKET -1
#endif



@implementation OFTCPSocket
+ tcpSocket
{
	return [[[OFTCPSocket alloc] init] autorelease];
}

#ifdef _WIN32
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
- init
{
	self = [super init];

	sock = INVALID_SOCKET;
	saddr = NULL;
	saddr_len = 0;
	cache = NULL;
	cache_len = 0;

	return self;
}

- free
{
	if (sock != INVALID_SOCKET)







<
<







45
46
47
48
49
50
51


52
53
54
55
56
57
58
- init
{
	self = [super init];

	sock = INVALID_SOCKET;
	saddr = NULL;
	saddr_len = 0;



	return self;
}

- free
{
	if (sock != INVALID_SOCKET)
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
						   andSize: size];
	}

	/* 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;

	if (sock == INVALID_SOCKET)
		@throw [OFNotConnectedException newWithClass: isa];







<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







222
223
224
225
226
227
228






















































































































229
230
231
232
233
234
235
						   andSize: size];
	}

	/* This is safe, as we already checked < 1 */
	return ret;
}























































































































- (size_t)writeNBytes: (size_t)size
	   fromBuffer: (const char*)buf
{
	ssize_t ret;

	if (sock == INVALID_SOCKET)
		@throw [OFNotConnectedException newWithClass: isa];